今更の話題ですが、CustomTabsIntentにダークテーマ用メソッドが増えていることに気づき、どういうことができるのかを今一度整理してみようと思います。
ダークテーマ対応のメソッドについては、androidx.browser:browser:1.2.0で追加されています。
https://developer.android.com/jetpack/androidx/releases/browser#1.2.0
また、従来ツールバーの色を設定するために使用していたsetToolbarColor
などのメソッドがDeprecatedになっており、代わりにsetDefaultColorSchemeParams
などの新メソッドを使うことが推奨されるように変わってきています。
検証用のアプリはこちら、また、CustomTabsのインターフェースを実装した、というか、それ以外の機能の無いブラウザーのソースコードはこちら。いずれもMIT Licenseで公開していますのでご参考まで。
また、CustomTabsの機能の中には説明が全く無い、もしくは、あってもコメント程度で、どうやって使うのか分からないメソッドや、どういう意味があるのか分からないコールバックといったものが結構あります。将来の拡張のためなのか、Chromiumのソースコードを調べても未実装だったというものもあります(調べたのが結構前なので今どうなっているか分かりませんが)。その辺は詳細不明と書いていますのでご容赦ください。
基本的使い方
詳細は省略しますが、基本的な使い方を抑えておきます。
サービスのバインド
プロセス間通信による機能を使う場合、サービスのバインドを行います。
単にCustomTabsのUIを使いたいだけの場合、これは必須ではありません。
object CustomTabsHelper : CustomTabsServiceConnection() {
fun bind(context: Context, packageName: String) {
CustomTabsClient.bindCustomTabsService(
context.applicationContext,
packageName,
this
)
}
override fun onCustomTabsServiceConnected(name: ComponentName, client: CustomTabsClient) {
client.warmup(0)
session = client.newSession(null)
}
}
ブラウザーの起動
上記、サービスのバインドを行い、sessionを取得している場合は、それをBuilderに渡すことで、バインドしているブラウザーアプリを起動することができます。
CustomTabsIntent.Builder(session)
// 様々なオプション設定
.build()
.launchUrl(context, url)
sessionがない場合も、起動したいブラウザーのパッケージ名を直接指定することで、CustomTabsの呼び出しをすることができます。
val customTabsIntent = CustomTabsIntent.Builder()
// 様々なオプション設定
.build()
customTabsIntent.intent.setPackage(browserPackageName)
customTabsIntent.launchUrl(context, url)
UIのカスタマイズ
CustomTabsIntent.Builderに対して様々な設定を行うことで表示されるUIのカスタマイズを行うことができます。
サービスの機能
あまりクローズアップされることはないですが、結構需要な機能があります。
CustomTabsClient
メソッド | 機能 |
---|---|
warmup(flag) | ブラウザーアプリに起動の準備をリクエストします。起動前の初期化までを先に行わせておくことで、起動が速くなります。long型引数がありますが、「Reserved for future use.」とのことなので適当に0とかを入れておけば良いです。 |
newSession(callback) | ブラウザーアプリとの間でセッションを作成します。引数のcallbackはNullableなので必要なければnullで問題無いです。Callbackを渡せば様々なイベントを受け取ることができるようになります。 |
extraCommand(command, args) | 「Can be used as a channel between the Custom Tabs client and the provider to do something that is not part of the API yet.」らしいです。ブラウザーとアプリの提供元で連携すれば何かに使えるのでしょうか。詳細不明 |
コールバックについては別途説明します。それ以外で特に詳細を説明できそうなものもないので次に行きます。
CustomTabsSession
メソッド | 機能 |
---|---|
mayLaunchUrl(url, extras, otherLikelyBundles) | これから要求する可能性のあるURLを伝えます。先読みを行うなどで読み込みを高速化させることができます。 |
requestPostMessageChannel(postMessageOrigin) | 「Sends a request to create a two way postMessage channel between the client and the browser.」らしいです。詳細不明 |
postMessage(message, extras) | 前述のメソッドで作ったチャンネルを使ってメッセージを送信する、同様に詳細不明 |
validateRelationship(relation, origin, extras) | Digital Asset Linksを使って呼び出し元アプリとoriginの間の関係性の検証をリクエストする。多分AppLinksの検証をリクエストするってことでしょうけど、よく分かりません。 |
receiveFile(uri, purpose, extras) | Intentでは渡せないような、大きなファイルを渡すらしいですが、詳細不明 |
setActionButton(icon, description) setSecondaryToolbarViews(removeViews, clickableIDs, pendingIntent) setToolbarItem(id, icon, description) |
後述のUI設定と同じメソッドの一部が用意されており、動的にUIを変更することができるようです。具体的なユースケースが分からず試していないです。 |
ってことで不明だらけで、分かっているのはmayLaunchUrlぐらいでしょうか?
mayLaunchUrlの第一引数はUriで、開く可能性の一番高いURLを渡します。第二引数はreserveなのでnullを渡しておきましょう。第三引数に第一引数以外に伝えたいURLを渡しますが、型がListです。このBundleはkeyをCustomTabsService.KEY_URLとして、UriをParcenableとして格納したBundleです。正直なぜUriのリストにしなかったのかと疑問ですが、以下のように詰め替えして渡します。
session.mayLaunchUrl(
Uri.parse(url),
null,
listOf(...)
.map { Uri.parse(it) }
.map { Bundle().also { it.putParcelable(CustomTabsService.KEY_URL, it) } }
)
CustomTabsCallback
CustomTabsClient#newSession() に渡すコールバックです。様々なイベントを受け取ることができます。
メソッド | 機能 |
---|---|
onNavigationEvent(navitationEvent, extras) | ブラウザーで発生したイベントが通知されます。定義されているイベントについては後述。extrasにはkey:timestampUptimeMillis でイベント発生のタイムスタンプとおぼしき値が入っています。 |
extraCallback(callbackName, args) | 任意のコールバック、CustomTabsSession#warmup()の結果、onWarmupCompleted (引数null)、メニューからブラウザーで開く、をしたときにonOpenInBrowser (引数:timestampUptimeMillis)が呼び出されました。 |
extraCallbackWithResult(callbackName, args) | 結果を返す任意のコールバック呼び出しですが、詳細不明 |
onMessageChannelReady(extras, extras) | CustomTabsSession#requestPostMessageChannel()の結果コールされるのだと思いますが、詳細不明 |
onPostMessage(message, extras) | CustomTabsSession#postMessage()関連だとは思いますが、詳細不明 |
onRelationshipValidationResult(relation, requestedOrigin, result, extras) | CustomTabsSession#validateRelationship()の結果呼び出されるらしいですが、詳細不明 |
onNavigationEventのイベントとしては以下が定義されています。
イベント | 意味 |
---|---|
NAVIGATION_STARTED | 読み込み開始 |
NAVIGATION_FINISHED | 読み込み完了 |
NAVIGATION_FAILED | 読み込み失敗 |
NAVIGATION_ABORTED | ユーザー操作により読み込みが中断(リンククリックやリロードなど) |
TAB_SHOWN | タブが表示された |
TAB_HIDDEN | タブが非表示になった |
ということでざっとまとめました。
プロセス間通信周りは不明なところが多くすみません。詳細をご存じの方がいらっしゃればコメント等で教えていただければと思います。