ボクココ

熱海で開発するブログ

Twilio でアプリ内通話の実現に向けて

目標

Twilio を使って、LINE のようなアプリ内通話を実現したい!

※まだ設計段階なので、見落としている部分があるかもしれません。その時は適宜修正, 更新します。

登場人物

通話を実現するには以下のものが必要

  • Device A (発信側)
  • Device B (受信側)
  • API (自社サーバ)
  • Twilio

概略図

f:id:cevid_cpp:20141022001444j:plain

以下にそれぞれの流れを整理する。

1, AさんがBさんへ通話ボタンを押す(Aさんアプリ内)

その瞬間、APIへ接続する。

2, APIがTwilioと接続し、AさんとBさんそれぞれのケーパビリティトークンを取得

ケーパビリティトークンというのを利用し、各端末は電話を発信したり受信したりできる。そのため電話するにはこれを発行する必要がある。

Aさん用のケーパビリティトークンは、AccountSid, AuthToken, AppSid の3つを指定して生成する。AppSid は Twilio サービス内のTwiMLAppのidで、音声通話URLと連動している。これが5と関わる。

Bさん用のケーパビリティトークンは、AccountSid, AuthToken, ClientName の3つを指定して生成する。ClientName は5で電話のかけ先に使うための識別子だ。通話の毎にユニークになればいいっぽい。

3, Aさん、Bさん端末へケーパビリティトークンを送信

Aさんに対してはAPIのレスポンスという形でケーパビリティトークンを返せば良いだけ。

Bさんに対してはプッシュ通知でケーパビリティトークンを送信する。ここがやや面倒。

4, 受け取ったAさんBさんそれぞれの端末で通信(connect)

ケーパビリティトークンがそれぞれの端末で取得できれば、それを使ってTwilio クライアント SDKにある Device を作成することができる。

発信側のAさん端末で connect() を呼ぶと、Twilio サーバ側で AppSid に紐づいた 音声通話URL へリクエストを投げる。このリクエストの向き先を自分の所のAPIへリクエストを投げるように設定する。これはTwilioの管理画面から設定する。下の音声通話の部分。

f:id:cevid_cpp:20141022004433p:plain

Bさんの方もプッシュ通知を受け取ったら、Deviceを登録しておく。また、受信時の起動アクティビティを登録しておく。

5, Twilioから受けたリクエストを TwiML で返す

AさんからTwilioへ接続する際に、Bさんのケーパビリティトークンを生成する時に使ったClientNameを付与して送信する。自分のサーバでは<Dial>の<Client>タグを生成し、その中に送られてきたClientNameを表示する。そうするとTwilioはBさんへ電話をかけてくれる。

6, 受信画面を表示

うまくつながれば、BさんのDevice登録時に指定した受信時のアクティビティが起動されるはずだ。

マテリアルデザインを試みたアプリを公開しました

先ほどマテリアルデザインっぽくデザインしたアプリ「グラッチェ! 〜青春 Q&A アプリ〜」を公開しました。

その経緯について記します。

AppCompat でマテリアルデザインを試す

Android 5.0 Lollipop の SDK と、新しい Nexus プレビュー版イメージを公開しました - Google Developer Japan Blog

上記の記事を読むと、こんなことが書かれています。

Android v7 appcompat Support Library、Material Design テーマの下位互換機能

おぉ下位のAndroidアプリでもマテリアルデザイン使えるのか!ということで興奮しながら 最新のappcompat をAndroid SDK Manager からインストール。

後は以下の記事を読みながら色々試行錯誤してみた。

appcompat v21: material design for pre-Lollipop devices! - Chris Banes

結論を言うと、これが全く上手く行かずww 最新のAndroid 5 SDK入れてもなんかStyleのエラーが出たり、出ないように消して動かしてもマテリアルデザインに適用されていなかったり。。ちょっと挑戦するのが早すぎました。

でもマテリアルデザインにしたい!ということで以下のOSSを使いました。

マテリアルデザインっぽくしてくれるOSS

ダイアログ: lewisjdeane/L-Dialogs · GitHub

Toast: MrEngineer13/SnackBar · GitHub

View: traex/RippleEffect · GitHub

特に、RippleEffect はめちゃめちゃ良かったです!これを入れるだけでマテリアルデザインっぽいアプリができます。タップした瞬間にまるで水に石を投げた時のような波紋が広がります。これものすごい気に入りました。

所感

これから色々なアプリがマテリアルデザイン化されていくと思いますので、その知見が貯まり次第、また最新SDKのホンモノのマテリアルデザインに挑戦してみます。

にしてもたくさんアプリ作ってくると、どんどんクオリティーが上がっていく気がしている。やはりこういうアプリの見た目も含め、経験って大事だなと感じる今日この頃。

東京中央区付近でできるフットサル・ソサイチのまとめ

秋と言えば「スポーツの秋」!ということで個人で気軽に参加できるフットサル・ソサイチをまとめてみました。料金は成人男性を対象としていますので、女性や学生等はサイトを参照してください。

アイリ個人参加フットサル(屋内)

フットサル個人参加 渋谷 日本橋 (東京)【AIRI 個人参加型フットサル】【個サル】

自分が一番お世話になっている個人参加フットサル。レベルはエンジョイ。6人*4チーム計24人でコートちょっと広めでフットサルをします。中央区民であれば中央区スポーツセンターでやっているこの個人参加が一番近くて気軽に参加できると思います。平日夜・土日と開催頻度もかなりあるので、フットサルしたいと思った時に行けます。

2000円2時間

ちなみに自分は30回一括のチケットを買っています。そうするとちょっと安くなります。また、カードがあって5回行くと500円割引になります。

両国インドアコート(屋内)

フットサル東京両国 - FUTSAL POINT 両国インドアFコート 個人参加

最近見つけた穴場。フットサルで検索しても出てきません。ここの魅力はガチ個サルがあることですかね。もちろん通常の個サルもやってます。ただ個人参加は月曜のみです。場所は両国ですが、墨田川渡ってすぐなので近いです。

1900円(エンジョイは1時間半、ガチは2時間)

現在、早めに予約すると1600円になるキャンペーンをやっているみたいです。

MIFA Football Park(屋外)

個人参加 | MIFA Football Park

豊洲にあるフットサル場。ここの魅力はなんと、ソサイチもやっている点です。ただし、月1と頻度がめっちゃ低いです。ただ普通の個人参加フットサルに関してもレベル別に丁寧に別れているので、超初心者でも気軽に参加できるのではないでしょうか。

1500円2時間

The 銀座deフットサル(屋外)

The 銀座deフットサル(プランタン銀座屋上)の個人参加情報・予約 - LaBOLA

有楽町駅付近にあるフットサル。個人参加は平日のお昼が中心みたいですね。そして参加者そんな多めではなさそうなので、たくさんフットサルできそうな感じがします。 レベルに関しては超初級〜エンジョイまでっぽいです。

ここは何と言っても値段が安い!こんな注意書きもありました。

※予約が少なくても スタッフを含めて8名以上になる場合は、4vs4で開催します!(半額でOK)

1350円 2時間

TOKYO SOCIETY CLUB 個人参加ソサイチ(屋外)

個人参加ソサイチ -東京でソサイチするならここ!!-

ソサイチをしたい!という場合は豊洲のここ。早めに予約すればなんと1000円でできるみたいです。毎週土曜日の19時からと決まった時間でやっているようです。

1500円2時間

RAKUTENICH FUTSAL(屋外)

RAKUTENCHI FUTSAL COURT | 楽天地フットサルコート 錦糸町 個人フットサル

錦糸町にあるフットサルコート。毎週火曜日は上級として解放しているようです。それ以外でも平日の夜にみっちりフットサルできるようです。

1500円2時間

所感

どうしても中央区内だと限られてしまいます。ただ江東区付近にお住まいの方はかなり豊富のフットサルコートあるので、電車でさくっといくのもいいかもですね。今回の個人参加フットサル選定の上で、他のもあったりしたのですが、値段や自分の家の近くかどうかといった判断基準から外させてもらいました。基本的にグーグルでフットサル 個人参加で検索すれば出てきますので、その他の所も考慮に入れて頂ければと思います。

個人的にはたまにはサッカーもしたいんですよね。個人参加サッカーはないものか。。22人という人数とサッカーコートを取るのが大変だからなかなかなさそうですが(・ω・ ;)

Android でのオブジェクトを保存する便利な方法

Android で端末にデータ保存をする時は以下の選択肢になるかと思う。

  • ファイルとして保存 (SDカードなど)
  • SQLiteデータベースに保存
  • SharedPreference に保存

それら一つ一つに長所・短所があり、使いどころがあるのだけれど、それぞれのメリットを合わせたような素晴らしいやり方があるので紹介。

Gson + SharedPreference

このコンボを利用することだ。具体的にはオブジェクトをJson化して保存し、読み込む時はそのJsonをパースするという方法。これで一気にオブジェクトの保存と復元が可能だ。しかも配列として復元することも可能なのでDBアクセスっぽいこともできる。

さてどうするか。コードを紹介しよう。

保存、取得コードの作成

ObjectStorage.java

public class ObjectStorage {

    public static void save(Object src, String key) {
        String json = new Gson().toJson(src);
        new CachePref().put(key, json);
    }

    public static <T> T get(String key, Class<T> klazz) {
        String jsonStr = new CachePref().get(key, "");
        if (jsonStr.equals("")) {
            return null;
        }
        return new Gson(),.fromJson(jsonStr, klazz);
    }

}

CachePref.java

public class CachePref {
    private final static String RPEF_NAME = "cache";
    private SharedPreferences pref;
    private SharedPreferences.Editor editor;

    public static final String KEY_USER = "user";
    public static final String KEY_USER_LIST = "user_list";

    public CachePref() {
        Context context = ApplicationController.getInstance().getApplicationContext();
        pref = context.getSharedPreferences(RPEF_NAME, Context.MODE_PRIVATE);
        editor = pref.edit();
    }

    public String get(String key, String defaultValue) {
        return pref.getString(key, defaultValue);
    }
    public void put(String key, String value) {
        editor.putString(key, value).commit();
    }
}

これだけだ!

ObjectStorage の利用

以下のようなモデルを用意しよう。

public class User {
    private String id;
    private String email;
    private String password;

    public String getId() {
        return id;
    }
    public String getEmail() {
        return email;
    }
    public String getPassword() {
        return password;
    }
}

そんでそれを読み書きしよう

// 単一
User user;
// userにデータ入れる

// 保存
ObjectStorage.save(user, CachePref.KEY_USER);

// 取得
user = ObjectStorage.get(CachePref.KEY_USER, User.class);


// 配列
User[] users;
// users にデータ入れる

// 保存
ObjectStorage.save(users, CachePref.KEY_USER_LIST);

// 取得
users = ObjectStorage.get(CachePref.KEY_USER_LIST, User[].class);

おわりに

これでSharedPreferenceの良さとDBの良さそれぞれを併せ持つ素晴らしいストレージが完成した。 もちろん、SQLiteに比べてselectを用いたデータアクセスができないという点はあるが、データ数が100個以内なら余裕でforで1件ずつアクセスしても良いと思う。

アップデートも削除も全部上書きすればいいだけなので、データ数の少ないオブジェクトの保存であれば、これで十分だと思う。

コネクシィではこのオブジェクト保存方法でたくさんのキャッシュを生成しております!

Android で Font Awesome を使うのがなかなかいい感じ

Android でアイコン作るときは、まぁ普通は Action Bar Icon Pack とかをよく使うと思う。自分もそれを好んで利用していた。

ただ、これには以下のような欠点がある。

  • 使う画像を利用する度にコピーするがだるい
  • 要領がどんどん大きくなる
  • 種類が少ない

さて、それらを解決してくれるのが Font Awesome を利用したアイコン生成方法だ。

設定方法

まずは Font Awesomeからアイコンパックをダウンロード。

その中の fonts -> fontawesome-webfont.ttf を Android プロジェクトの assets ディレクトリに保存。なければ java とかと同じ階層に作る。

使いたいアイコンを チートシート から探す。

strings.xml に以下を追記

    <string name="icon_fb">&#xf082;</string>

layout はこんな感じ

                <TextView
                    android:id="@+id/fb_icon"
                    android:text="@string/icon_fb"
                    android:textSize="@dimen/text_large"
                    android:textColor="@color/com_facebook_blue"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content" />

アクティビティ内に以下を記述

        Typeface font = Typeface.createFromAsset(getAssets(), "fontawesome-webfont.ttf");
        ((TextView) findViewById(R.id.fb_icon)).setTypeface(font);

すると、アイコンができる。

Font Awesome にすること

メリットは以下の通り。

  • 種類が多い
  • 容量節約
  • drawable へのコピペは不要
  • 色が自由自在
  • 大きさもdimens.xmlに書けば画面サイズ毎に大きさを変えられる

色変えられるのはかなりでかい!Actionbar icons pack じゃできなかった。

デメリットはこんなのかな

  • 毎回チートシート見てstringsに記入しないといけない
  • activityにコード書かないといけない

所感

アイコンのあるアプリは見た目がいいし、直感的にわかりやすし是非導入したい所。最初からFont Awesomeを利用したAndroidプロジェクトにすることをおすすめします。

自分の場合は一部Actionbar icons pack、一部はFont Awesome となってしまった。。Font Awesomeで統一しようかな〜。

REST な API とは何か

以前、こんな REST API を作って欲しいと言われて、その仕様をみたらこの方は本当にRESTの意味をわかっているのかと疑問になる設計だった。意外とRESTって言葉は流行っていても、それが一体なんなのかしっくり来ない方もいるようなので、ここでRESTについて自分なりの理解ではあるがまとめてみようと思う。

REST, それは資源、モノベースのURL

完全に間違えているREST とは例えば以下のようなURL設計だ。

GET  /api/listItem
GET  /api/showItem?id=xxxxx
POST /api/createItem
POST /api/updateItem?id=xxxxx
POST /api/deleteItem?id=xxxxx

この場合は、動詞があるのでぱっと見た感じ意味が分かりやすい。アイテム一覧、アイテム詳細、アイテム作成、アイテム更新、アイテム削除。 ただこれはRESTではなく、ただのAPIだ。正しくはこうだ。

GET /api/items
GET /api/items/xxxxx
POST /api/items
PUT /api/items/xxxxx
DELETE /api/items/xxxxx

このように、 items というアイテム(資源)の集合をHTTPメソッドを用いてURLに設計にするのがRESTというものだ。APIのURLに動詞が入っている場合は注意だ。間違っている可能性が高い。

さて、RESTを意識してもだんだんと難しい場合が出てくる。次の例に行こう。

ネストされたリソース

ユーザーに対してその人の持つその他の資源についてどうURLで表現すれば良いのだろうか。 例えば以下のようなURLを見てみよう。ありがちなパターン。

GET  /api/coupon?user_id=xxxxx
POST /api/coupon?user_id=xxxxx
PUT /api/coupon?user_id=xxxxx&coupon=yyyyy

上から順に、自分のクーポンコードの取得、クーポンコードの生成、クーポンコードの適用といった想定だ。まぁこれでも悪くはないんだけど、RESTっぽくするにはもっとusersとの関連を示すべきだ。自分の理想は以下の通り

GET  /api/users/xxxxx/coupon
POST /api/users/xxxxx/coupon
PUT /api/users/xxxxx/coupon?coupon=yyyyy

こんな感じでURLを設計すれば、ほっとんどのことはRESTの設計で作ることができる。今までURLの作り方はかなり自由で悩んでいた人も多いだろうが、このRESTの制約を守るとかなり規則的にURLを設計することができる。新しいURLを作成する際に、何の資源に対してのリクエストなのか、というのを常に考えるようにしよう。

RESTのメリット

ではRESTにすると何が嬉しいのか。

その一つはさっき述べたように、URL設計に規律が生まれるという点だ。URLを見た時点で、ソースコードのどの部分なのかがはっきりわかる。ルーティングでごにょごにょしているコードを読む必要が無くなる。

そしてもう一つがそのAPIクライアントのメリットだ。規律を守ったURLにすることで、RESTのAPIクライアントを作成もしくはGithubなどから拝借するだけで簡単にAPI通信処理のコードを書くことができる。これも規約があるからこそコードの共通化をすることができるのだ。

まだ慣れないうちは、どうやってこれをURL設計すれば良いのかわからないかもしれない。そんな時は是非Twitterなりでコンタクト取って頂ければ、一緒に考えることはできるので連絡頂きたい。

いつも2番であるという心理

何かしらのコンテストや舞台に立つと、自分はほんとしょっちゅう2位、もしくはギリギリだ。これが驚くくらいの確率で。それはもう中学時代からそうだった。

  • ハンドボールでは毎回優勝できずに2位か3位
  • 高校受験ではまさかの滑り止め的なのに落ちたけど第二志望に合格
  • ビジネスプランコテンスト2位
  • 開発コンテスト2位

そして今日のハッカソンでも2位だった。

どういう時にダメなのか

ようやく最近、それがパターン化されていることに気づいた。どういう時にこうなるかというと、「これは絶対俺が1位だ!」と内心確信している時だ。めっちゃ準備してもう大丈夫だという所で優勝間違いないと思ってたら、2位になった。そういう展開が今まであまりにも多すぎる。

逆に受験や、前の会社でのTOEIC試験の時のように、「これはマジでヤバい」と思った時はとんでもないパフォーマンスを発揮する。ただし自分の場合は何事も事前によく準備しちゃうので、ヤバいって状況にはなかなかならんのよね。。時間ギリギリに何かやるとか大嫌いな性格なもので。

どうすればいいんだ!?

そう考えると常に1位を取るにはどうしたらいいのだろうか。今までの経験則から言えば、「準備するけどギリギリまでヤバいと思い続ける」という方法になるだろう。

自分の満足点を常に高くしておいて、これじゃまだまだダメだって思い続ける。今の自分だと2位になれる所で満足してしまっているということ。これを1位にするためにはもっともっと上の満足点を自分の心の中に持っていないといけない。

そのための具体的なアクションが思いつかない。。ただコンテストやそういった類いの度に、これで満足しちゃいけないって心の中に思う癖をつける必要はあるな、と感じている。