最終更新日:190227原本2015-05-13 

Chromecastアプリ開発入門:
Google Cast SDKを使ったAndroid/iOSアプリの作り方と注意点 (2/6)

Androidアプリ開発方法

 次に、AndroidでのSenderアプリの開発方法について解説します。

依存ライブラリ

 まず、Google Cast SDKが外部依存するライブラリを取り込む必要があります。

依存ライブラリの種類と、それぞれの役割は次の通りです。

  • Android Support Libraries(rev 19.0.1以上)
    • android-support-v7-appcompat
      • Android 2系でActionBarを表示するためのライブラリ
      • CastアイコンをActionBarに表示するために使う
    • android-support-v7-mediarouter
      • Androidスマートフォンが外部スピーカーなどの外部出力デバイスの検出・接続を管理するライブラリ
      • Chromecastとの接続やCastアイコンなどのUI表示に使う
  • Google Play services SDK(rev 4.2 以上)
    • google-play-services_lib
      • Google Play Servicesの機能を使うためのライブラリ
      • Google Cast Android APIを提供する
      • Receiverアプリの起動やReceiverアプリとの通信など、Chromecastの主機能を使うために必要

 Receiverアプリとの通信はWebSocketで行いますが、アプリ開発者は上記ライブラリのAPIを使うことでWebSocketを意識することなくプログラミングできます。

 Google Cast SDK自体はGoogle Play Services SDKに同梱されているため、個別にインストールする必要はありません。ただし、Google Play Servicesに依存するため、ユーザーが「Google Play 開発者サービス」をアンインストールしたり無効にしている場合はChromecastの機能が使えない可能性があります。

コラム「Google Play Servicesとは」

 Google MapsやGoogle+、Google Castなど、グーグルが提供するサービスを使ったアプリを開発できる仕組みです。Androidスマートフォンには、アプリ開発者が作ったアプリとは別にGoogle Play Servicesのアプリがインストールされており、バックグラウンドで常駐しています。

 Androidの設定画面からアプリ一覧を見ると「Google Play開発者サービス」と表示されているのが、Google Play Servicesのアプリです。アプリ開発者が作ったアプリは、「Google Play開発者サービス」を介することで、これらのサービスを使えるようになります。「Google Play開発者サービス」は自動で更新されるため、アプリ開発者は自身のアプリをアップデートすることなく常に最新バージョンのサービスを使えます。

 これらのライブラリの具体的な取り込み手順については、開発環境(Eclipse/Android Studio)によっても異なるため、ここでは説明を省きます。グーグルが公開しているSupport Library SetupAndroid Sender App Developmentを参照してください。

 次に、具体的な実装を見ていきます。

Chromecastデバイスでの接続概要

 まずはChromecastデバイスの検索・接続・Receiverアプリの起動までを説明します。ユーザーがChromecastと接続するときはCastアイコンを使いますが、Castアイコンの実装方法には次の3通りがあります。

  1. MediaRouteActionProviderを使い、標準的なCastアイコンが組み込まれたActionBarを設置する
  2. MediaRouteButtonを使い、ActionBar以外の任意の場所に標準的なCastアイコンを設置する
  3. MediaRouterのAPIを使い、Castアイコンの機能を持った独自UIを開発する

 1と2では、Castアイコンをタップした後、標準的なCastメニューが表示される部分も組み込まれています。3は、UIとは独立したベーシックなAPIだけを使って開発する方法で、Castアイコン・Castメニューを含めUI部分を全て自前で作成する必要があります。

 公開されているサンプルプログラムMediaRouter-Cast-Button-androidにそれぞれの実装例が記述されています。

 本記事では、接続に関する最低限の実装方法を理解してからUI部分について知ってもらうため、始めに3の方法を解説した後、1のMediaRouteActionProviderを使った方法を示します。

MediaRouterによるChromecastデバイスの検出と接続先選択

 中心となるクラスはandroid-support-v7-mediarouterライブラリのMediaRouterクラスで、このクラスがChromecastを含めたマルチメディアの外部出力先の検出をつかさどります。その他、外部出力先を検索する条件を表したMediaRouteSelectorクラスや、検索結果が得られたときなどのコールバックを記述するMediaRouter.Callbackクラスを使います。

 まず、それぞれのクラスのインスタンスを取得/生成します(コード1)。

  1. mMediaRouter = MediaRouter.getInstance(getApplicationContext()); //【1】
  2. mMediaRouteSelector = new MediaRouteSelector.Builder().addControlCategory(
  3. CastMediaControlIntent.categoryForCast(APPLICATION_ID)).build();//【2】
  4. mMediaRouterCallback = new MyMediaRouterCallback();//【3】
コード1 MediaRouterインスタンス取得

 【1】でMediaRouterクラスのインスタンスを取得し、【2】【3】でMediaRouteSelector、MediaRouter.Callbackクラスのインスタンスを生成しています。【3】のMyMediaRouterCallbackクラスはMediaRouter.Callbackインターフェースを実装したクラスで、詳細は後に記します。

 【2】では、Builder()メソッドを使ってMediaRouteSelectorクラスをインスタンス化する際、「media control category」という外部出力先の種類を示す文字列を指定しています。ここではChromecastデバイスを検出したいので、CastMediaControlIntentクラスのcategoryForCast()メソッドを使ってChromecast用の文字列を生成しています。

 具体的には「com.google.android.gms.cast.CATEGORY_CAST/{Application ID}」のようなReceiverアプリのApplication IDを付与した文字列となっています。

 注意点として、MediaRouterをimportするパッケージは「android.support.v7.media.MediaRouter」としてください。誤って「android.media.MediaRouter」をimportしてはいけません。

 次にMediaRouteSelector、MediaRouter、MediaRouter.Callbackのインスタンスを関連付け、デバイス検出時などにコールバックが呼ばれるようにします。通常はActivityのonResume()メソッドで実装します(コード2)。

mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
コード2 MediaRouterのコールバック設定

 一方、ActivityのonPause()メソッドでは、次のようにデバイス検出のコールバックを解除する処理を行います(コード3)。

mMediaRouter.removeCallback(mMediaRouterCallback);
コード3 MediaRouterのコールバック解除

 MediaRouter.Callbackの実装クラスMyMediaRouterCallbackでは、以下のコールバックメソッドをオーバーライドします(コード4)。

  1. private class MyMediaRouterCallback extends MediaRouter.Callback {
  2. @Override
  3. public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
  4. // 新たなCastデバイスが見つかったときに呼ばれる
  5. Log.d(TAG, "onRouteAdded: info=" + info);
  6. // 見つかったデバイスの情報を保持
  7. mMediaRoutes.add(info);
  8. }
  9. @Override
  10. public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
  11. // 見つかっていたCastデバイスを見失ったときに呼ばれる
  12. Log.d(TAG, "onRouteRemoved: info=" + info);
  13. // 見つかったデバイスの情報を削除
  14. mMediaRoutes.remove(info);
  15. }
  16. @Override
  17. public void onRouteSelected(MediaRouter router, RouteInfo info) {
  18. // 接続先Castデバイスを選択したときに呼ばれる
  19. Log.d(TAG, "onRouteSelected: info=" + info);
  20. // 選択したデバイスを保持
  21. mSelectedDevice = CastDevice.getFromBundle(info.getExtras());
  22. }
  23. @Override
  24. public void onRouteUnselected(MediaRouter router, RouteInfo info) {
  25. // 接続先Castデバイスの選択を解除したときに呼ばれる
  26. Log.d(TAG, "onRouteUnselected: info=" + info);
  27. mSelectedDevice = null;
  28. }
  29. }
コード4 MediaRouter.Callback実装

 Castアイコンの表示は、onRouteAdded()メソッドが呼ばれて検出済みのデバイスが一つでも得られたときに行うといいでしょう。

 Castメニューで検出したChromecastデバイスの一覧を表示できるよう、onRouteAdded()メソッドの引数に渡されたMediaRouter.RouteInfoインスタンスを保持しておきます。ユーザーがデバイスの一覧をタップして接続先デバイスを選んだときは、次のようにMediaRouterインスタンスに対して選んだ接続先デバイスを教えます(コード5)。

  1. MediaRouter.RouteInfo info = mMediaRoutes.get(selected); //ユーザーが選択したデバイスに関するRouteInfoを得る
  2. mMediaRouter.selectRoute(info); //MediaRouterに選択したデバイスを教える
コード5 選択したデバイスの設定

 selectRoute()を実行すると、onRouteSelected()メソッドが呼ばれる仕組みです。

 以上でMediaRouterに対して接続先デバイスを指定することができました。

Chromecastデバイスとの接続とReceiverアプリの起動

 次にChromecastデバイスと接続し、Receiverアプリを起動します。

 中心となるクラスはgoogle-play-services_libライブラリのGoogleApiClientクラスです。このクラスはChromecastを含むGoogle Play servicesを使うための窓口となるクラスです。

 まず、必要なクラスのインスタンスを生成します(コード6)。

  1. mCastClientListener = new CastListener();
  2. mConnectionCallbacks = new ConnectionCallbacks();
  3. mConnectionFailedListener = new ConnectionFailedListener();
  4. Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions.builder(
  5. mSelectedDevice, mCastClientListener);
  6. mApiClient = new GoogleApiClient.Builder(this)
  7. .addApi(Cast.API, apiOptionsBuilder.build())
  8. .addConnectionCallbacks(mConnectionCallbacks)
  9. .addOnConnectionFailedListener(mConnectionFailedListener)
  10. .build();
コード6 GoogleApiClientのインスタンス生成

 CastListener、ConnectionCallbacks、ConnectionFailedListenerは、それぞれCast.Listener、GoogleApiClient.ConnectionCallbacks、GoogleApiClient.OnConnectionFailedListener、で定義されているIFを実装した自作クラスで、Chromecastデバイスとの通信結果や、Receiverアプリの状態変化などのコールバックを実装しています。

 各コールバックの実装例は次の通りです(コード7)。

  1. private class CastListener implements Cast.Listener {
  2. @Override
  3. public void onApplicationStatusChanged() {
  4. // Receiverアプリの状態が変わったときに呼ばれる
  5. Log.d(TAG, "onApplicationStatusChanged");
  6. }
  7. @Override
  8. public void onVolumeChanged() {
  9. // Receiverアプリの音量が変わったときに呼ばれる
  10. Log.d(TAG, "onVolumeChanged");
  11. }
  12. @Override
  13. public void onApplicationDisconnected(int errorCode) {
  14. // Receiverアプリとの接続が切断したときに呼ばれる
  15. Log.d(TAG, "onApplicationDisconnected");
  16. }
  17. }
  18. private class ConnectionCallbacks implements
  19. GoogleApiClient.ConnectionCallbacks {
  20. @Override
  21. public void onConnected(Bundle connectionHint) {
  22. // Chromecastデバイスとの接続が成功したときに呼ばれる
  23. Log.d(TAG, "onConnected");
  24. }
  25. @Override
  26. public void onConnectionSuspended(int cause) {
  27. // Chromecastデバイスとの接続が途切れたときに呼ばれる
  28. Log.d(TAG, "onConnectionSuspended");
  29. }
  30. }
  31. private class ConnectionFailedListener implements
  32. GoogleApiClient.OnConnectionFailedListener {
  33. @Override
  34. public void onConnectionFailed(ConnectionResult result) {
  35. // Chromecastデバイスとの接続に失敗したときに呼ばれる
  36. Log.d(TAG, "onConnectionFailed");
  37. }
  38. }
コード7 Cast.Listener実装

 GoogleApiClientをインスタンス化したら、次のようにしてChromecastデバイスと接続します(コード8)。

mApiClient.connect();
コード8 Chromecastデバイスとの接続

 接続の結果によって、コード7のコールバックメソッドのいずれかが呼び出されます。

 接続が成功したら、次のようにしてReceiverアプリを起動します(コード9)。

  1. try {
  2. Cast.CastApi
  3. .launchApplication(mApiClient, APPLICATION_ID, false)
  4. .setResultCallback(
  5. new ResultCallback<Cast.ApplicationConnectionResult>() {
  6. @Override
  7. public void onResult(Cast.ApplicationConnectionResult result) {
  8. Status status = result.getStatus();
  9. if (status.isSuccess()) {
  10. // Receiverアプリ起動成功
  11. } else {
  12. // Receiverアプリ起動失敗
  13. }
  14. }
  15. });
  16. } catch (Exception e) {
  17. Log.e(TAG, "Failed to launch application", e);
  18. }
コード9 Receiverアプリの起動

 Cast.CastApiのlaunchApplication()メソッドにReceiverアプリのApplication IDを指定して起動します。setResultCallback()メソッドにはReceiverアプリ起動の結果を受け取るコールバックを設定します。

 これらのアプリ起動の処理は、コード7のonConnected()メソッドが呼ばれたタイミングで実行すればいいでしょう。

 以上がChromecastデバイスの検索からReceiverアプリの起動までの最小限の実装です。上記を応用すればChromecastデバイスとの接続機能を持ったUIを自由に開発できます。