はじめての Chrome Custom Tabs

この記事は RECRUIT MARKETING PARTNERS Advent Calendar 2015 の投稿記事です。

どうもこんにちわ。英単語サプリ担当 田澤です。

これまでアプリからWebサイトを表示するとなると、WebViewを使用するかIntentでブラウザアプリを呼び出すことで対応してきましたが、そういった従来の方法ですと以下のような課題が発生しがちです。

  • ブラウザアプリでは遷移してからWebサイトを表示するまでが重い、遅い
  • 別アプリの表示となるなのでUIに統一感を出せない
  • WebViewではセキュリティ、機能面に対する懸念がある

ChromeCustomTabsでは表示速度の向上、Choromeベースのセキュリティと機能(Chromeとのcookieの共有など)の恩恵を受けることができます。また、UIのカスタマイズも可能なためシームレスにWebページを表示することができます。

本記事ではChromeCustomTabsの簡単な使用方法、カスタマイズして表示する方法、PreFetch(先読み)について紹介します。

ここで使用しているコードは Github – SampleChromeCustomTabs で公開しています。

準備

まずはbuild.gradleに下記を追加します。

    compile 'com.android.support:customtabs:23.1.1'

サポートライブラリのみでも実装可能ですが、Googleが提供しているChromeCustomTabsのサンプルにSharedという便利なクラス群をまとめたmoduleが提供されているので追加します。

使用条件

Chromeがv45以上である必要があります。Chromeが対応していない、Chromeがインストールされていない場合は通常のIntentの挙動となり、ブラウザアプリが起動します。また、SupportLibrary 23.1.1のminSDkVersionが15となっているので、導入を検討する場合は対象となるアプリのminSDkVersionを確認しておきましょう。

使用方法

ChromeCustomTabsはWebViewのようにViewコンポーネントを配置しては使用せず、Intentベースでメッセージングする仕様になっています。

1. 簡単な使用方法

ただ表示するのみ場合だと、以下のコードのみで対応は完了します。ChromeCustomTabsを使用するのにインターネットパーミッションは不要です。

        CustomTabsIntent tabsIntent = new CustomTabsIntent.Builder().build();
        
        String packageName = CustomTabsHelper.getPackageNameToUse(this);
        tabsIntent.intent.setPackage(packageName);
        tabsIntent.launchUrl(this, uri);

まずCustomTabsIntentを生成します。CustomTabsIntentはWebサイトを表示を実行するのに使用します。後述の〈2. カスタマイズして表示する〉のとおり、設定できる内容が多いためBuilderパターンで生成できるように実装されています。

次にCustomTabsIntent.intentにパッケージ名を明示的に指定しています。パッケージ名の取得にはCustomTabsHelperクラスを使用します。これはSharedモジュールが提供しているクラスです。getPackageNameToUseメソッドはCustomTabへの接続先となる適切なChromeのパッケージ名を取得してくれます。端末によってはパッケージ名を指定しないとCustomTabが正しく動作せずブラウザアプリが起動することがありました。

CustomTabsIntentlaunchUrlメソッドを実行するとWebサイトが表示されます。

Default CutomtabDefault Cutomtab Menu

ChromeベースなのでデフォルトでpullToRefreshが実装されており、ページ内検索、翻訳機能も使用できます。デザイン面ではタイトル表示はURLのみ。CustomTabsを閉じるボタンのアイコンが×、Toolbarの色がグレーでアプリに統一感がなくなってしまっています。

そこで、次はCustomTabのカスタマイズ方法について紹介します。

2. カスタマイズして表示する

CustomTabsIntent.Builderには以下のメソッドが用意されており、カスタマイズが可能となっています。UIのカスタマイズ、遷移時のアニメーションの指定、アクションボタンとメニューアイテムの追加ができます。

メソッド名 機能
setShowTitle(boolean showTitle) Webサイトのタイトルを表示します
setToolbarColor(int color) Toolbarの色を設定します
setCloseButtonIcon(Bitmap icon) 閉じるボタンのアイコンを設定します
setStartAnimations(Context context, int enterResId, int exitResId) 表示アニメーションを設定します
setExitAnimations(Context context, int enterResId, int exitResId) 閉じるアニメーションを設定します
enableUrlBarHiding() 下にスクロールしたときにToolbarが非表示になるようにします
addMenuItem(String label, PendingIntent pendingIntent) メニューを追加します
setActionButton(Bitmap icon, String description, PendingIntent pendingIntent) アクションボタンを追加します
    CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();

    setupMenu(builder);
    setupActionButton(builder);

    CustomTabsIntent tabsIntent = builder.setShowTitle(true)
            .enableUrlBarHiding()
            .setToolbarColor(getResources().getColor(R.color.brand_sub))
            .setCloseButtonIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_arrow_back))
            .setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left)
            .setExitAnimations(this, android.R.anim.slide_in_left, android.R.anim.slide_out_right)
            .build();

    String packageName = CustomTabsHelper.getPackageNameToUse(this);
    tabsIntent.intent.setPackage(packageName);                
    tabsIntent.launchUrl(this, uri);

メニュー、アクションボタン共に追加するためのメソッドが用意されておりPendingIntentをセットして使用します。

// メニューの追加
private void setupMenu(CustomTabsIntent.Builder builder) {

    Intent menuIntent = new Intent();
	//...省略
    PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, menuIntent, 0);
    
    builder.addMenuItem("Menu Share Sample", pendingIntent);
}
// アクションボタンの追加
private void setupActionButton(CustomTabsIntent.Builder builder) {

    Intent actionIntent = new Intent(Intent.ACTION_SEND);
	//...省略
    PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, actionIntent, 0);
    Bitmap icon = BitmapFactory.decodeResource(getResources(), android.R.drawable.ic_menu_share);
        
    builder.setActionButton(icon, "Action Share Sample ", pendingIntent);
}

上記のように各種設定することで次のように表示が変わります。

Customize CutomtabCustomize Cutomtab Menu

 

ツールバーの色をアプリのテーマカラーに合わせる、画面遷移をアプリと同様のものにする、閉じるボタンのアイコンを変更することでアプリに統一感が出て、シームレスにWebサイトを表示することが可能となります。

3. PreFetch

ChromeCustomTabsの特徴の1つとしてPreFetchがあります。これはlaunchUrlを実行する前に、Webサイトの先読みをしておいて画面遷移時の表示速度の向上させる機能です。実行手順としてはWarm up→先読み→CustomTabを表示する、となります。

3-1. Warm upをする

    mCustomTabsServiceConnection = new CustomTabsServiceConnection() {
        @Override
        public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient customTabsClient) {
            mCustomTabsClient = customTabsClient;
            // Chrome と接続したらWarm upする
            mCustomTabsClient.warmup(0L);
            }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

   String packageName = CustomTabsHelper.getPackageNameToUse(this);
   // Chrome と接続
   CustomTabsClient.bindCustomTabsService(this, packageName, mCustomTabsServiceConnection);

まず、CustomTabsClient.bindCustomTabsServiceメソッドを実行し、Chromeと接続をします。第3引数にはCustomTabsServiceConnectionをセットします。

CustomTabsServiceConnectionはserviceのbindの状況を監視しており、onCustomTabsServiceConnectedonServiceDisconnectedでbindの結果を返してくれます。Serviceがbindされると、onCustomTabsServiceConnectedが呼ばれるのでCustomTabsClientを使用してWram upを行います。また、CustomTabsが不要になった時にServiceのunbindを忘れないようにしましょう。

    unbindService(mCustomTabsServiceConnection);

3-2. 先読みして表示

Warm upができたので次は先読みを行います。

    mCustomTabsSession = mCustomTabsClient.newSession(null);

CustomTabsClientnewSessionメソッドからSessionの生成を行います。newSessionメソッドの引数の型はCustomTabsCallbackクラスです。このクラスはCustomTabのNavigationEventのタイミングでコールバックを返してくれます。

NavigationEventにはNAVIGATION_STARTEDNAVIGATION_FINISHEDTAB_SHOWNなどがあり、Webページの読み込み開始、完了やCustomTabの表示時などのタイミングでイベントをキャッチできます。不要な場合はnullを指定します。

次に、生成したSessionを使用して先読みを行います。先読みをするにはmayLaunchUrlメソッドを実行します。このメソッドには戻り値があり、先読みが成功したかの結果が返却されます。

    boolean isSuccess = mCustomTabsSession.mayLaunchUrl(URI, null, null);

先読みができたらlaunchUrlメソッドを使用してCustomTabを表示します。この時CustomTabsIntent.Builderの引数にSessionを指定するのを忘れないようにしましょう。

    CustomTabsIntent tabsIntent = new CustomTabsIntent.Builder(mCustomTabsSession).build();
    // 省略
    tabsIntent.launchUrl(this, uri);

これでWebサイトの先読みがされた状態でCustomTabが表示されます。

先読みの効果を確認するため、ブラウザ、PreFetchをしたChromeCustomTabs、WebViewで表示速度を比較しました。

( クリックして動画を再生 )

PreFetchによる表示速度の向上がよくわかります。(使用端末:Galaxy S5)

まとめ

ChromeCustomTabsはUIの容易なカスタマイズによりシームレスな画面遷移を表現できる、Chromeの機能が使用できる、WebViewのセキュリティリスク回避ができる、PreFetchによる表示高速化ができる点など有用なコンポーネントです。しかし、PreFetchはどのタイミングで実行するのかが悩ましいです。
無闇矢鱈にPreFetchを行うと実際はWebサイトを読み込むところまでユーザーが到達しないのに、先読みだけしてしまい無駄な通信を発生させることになってしまいます。
また、Chromeがインストールされていない、バージョンが古いとブラウザが起動することになるのでChromeCustomTabsありきの実装はできません。対象外の端末に対してどのようにアプローチするのかを考える必要があります。

便利と言えば便利ですが、どのように扱うか、使用することで何を実現したいのかをよく検討してから取り入れたいところです。

田澤健二

Lv.
4
EXP.
1,319

Androidアプリの開発しています。

この執筆者の記事一覧

コメントはこちらのに同意の上、投稿ください。

この記事を読んだ人はこんな記事も読んでいます