Chrome Custom Tabs を試してみる -プリフェッチ編-


DroidKaigi 2016アプリでも使われており注目を集めていると思われるChrome Custom Tabsですが、
[デベロッパページ](https://developer.chrome.com/multidevice/android/customtabs)にあるような高速でWebページを表示しいたい場合、単純にCustomTabsIntent使うだけではこのようになりません。

![image](https://developer.chrome.com/multidevice/images/customtab/performance.gif)

今回の記事は、高速化のためにCustom Tabsでプリフェッチをする方法についてです。
Chrome Custom Tabsの基本的な使い方については前回の記事をご参照下さい。

* [Chrome Custom Tabs を試してみる](http://qiita.com/droibit/items/66704f96a602adec5a35)

確認用のサンプルはGitHubにあります。

* [GitHub](https://github.com/droibit/customtabsoauth)

## プリフェッチの方法

プリフェッチする方法はデベロッパーページに載っています。

* [Warm up Chrome to make pages load faster](https://developer.chrome.com/multidevice/android/customtabs#warm-up chrome to make pages load faster)

デベロッパーページのように自前でChrome Custom Tabsが提供するクラスを使ってプリフェッチすることができますが、今回は手っ取り早く実現するために公式が提供しているプロジェクトにあるユーティリティを使用します。

* [chrome-tabs-client/demo](https://github.com/GoogleChrome/custom-tabs-client/tree/master/demos)
* [chrome-tabs-client/share](https://github.com/GoogleChrome/custom-tabs-client/tree/master/shared)


詳細を理解したいという方は、ユーティリティクラスのソースコードを合わせて読むと理解しやすいかもしれません。

ユーティリティはサポートライブラリとして提供されていないので、今回はファイルをコピーして使わせてもらっています。コピーするファイルは次のとおりです。

* demo
	* CustomTabActivityHelper.java
* share
	* CustomTabsHelper.java
	* KeepAliveService.java
	* ServiceConnection.java
	* ServiceConnectionCallback.java


主に使用するのは *CustomTabActivityHelper* クラスになります。

### セットアップの流れ

プリフェッチするための事前準備のおおまかな流れは次のようになります。

1. Custom Tabs Serviceに接続
2. Serviceにプリフェッチ対象のURLを指定
3. CustomTabsIntent生成時にセッションを指定して起動

#### Custom Tabs Serviceに接続

```java
public class MainFragment extends Fragment implements CustomTabActivityHelper.ConnectionCallback {

    private static final String sDevPageUrl = "https://developer.chrome.com/multidevice/android/customtabs";

	private CustomTabActivityHelper mCustomTabActivityHelper;
	
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        
        // サービスに接続された時に呼ばれるコールバックを設定する。
        mCustomTabActivityHelper = new CustomTabActivityHelper();
        mCustomTabActivityHelper.setConnectionCallback(this);
    }
    
    @Override
    public void onStart() {
        super.onStart();
        // Custom Tabs Serviceに接続する。
        mCustomTabActivityHelper.bindCustomTabsService(getActivity());
    }
    
    @Override
    public void onStop() {
        super.onStop();

		 // 切断はonStartと対になるonStopがいいと思われます。
        mCustomTabActivityHelper.unbindCustomTabsService(getActivity());
    }    
}
```

`onStart` のタイミングで接続するのはデベロッパーページの *Best Practices* に記載があるためです。
他にも情報がありますので一度ご覧になるといいと思います。

* [Best Practices](https://developer.chrome.com/multidevice/android/customtabs#bestpractices)

#### Serviceにプリフェッチ対象のURLを指定

```java
@Override
 public void onCustomTabsConnected() {
     Uri uri = Uri.parse(sDevPageUrl);
     if (mCustomTabActivityHelper.mayLaunchUrl(uri, null, null)) {
         Toast.makeText(getContext(), "Connected custom tabs service, and warm up OK.", Toast.LENGTH_SHORT).show();
     }
 }
```

#### CustomTabsIntent生成時にセッションを指定して起動

```java
private void showDeveloperPage() {
	CustomTabsSession sesstion = mCustomTabActivityHelper.getSession();
	CustomTabsIntent tabsIntent = new CustomTabsIntent.Builder(session)
			// 省略
			.build()

	// アクティビティの起動。
	Uri uri = Uri.parse(sDevPageUrl);
	CustomTabActivityHelper.openCustomTab(getActivity(), tabsIntent, uri, null);			
}
```

Activityの起動には `CustomTabActivityHelper.openCustomTab()` を使うこともできます。
`CustomTabsIntent#launchUrl()` とは違い、このメソッドは第4引数にCustom Tabsが有効ではない用のコールバックを指定することができます。

サポートライブラリをそのまま使うと結構大変なのですが、 `CustomTabActivityHelper` を使用することで
とても簡単にプリフェッチすることができます。

実際にChrome Custom TabsのデベロッパーページをCustom Tabsで表示してみます。
（1度目の表示はプリフェッチなし、2度目の表示はプリフェッチあり）

![Imgur](http://i.imgur.com/yVKnIoL.gif?1)

プリフェッチが効いている2度目の表示はかなり高速化されています。

以上、簡単ですがCustom Tabsでプリフェッチする方法でした。