todo-add-alt

Trusted Web Activityを触ってみる

手探りでPWAをアプリ化してみる作業ログ

June 17, 2020

暑くなってきましたね。なんか昨夜暑すぎて非常に寝苦しかったので、就寝をあきらめ、今まで「時間がない」を言い訳に着手していなかった技術検証を寝落ちするまでひとまず進めてみようと一人立ち上がったオジサンが私です。お久しぶりです。こちら改めまして 「会社の意見は一切代表していませんし、ありません。すべて私の個人的な見解です。」 な技術検証作業ログです。

実は2017年ごろにコンセプトが公開されたTrusted Web Activityという「フルスクリーンなChromeを一つのActivityとして立ち上げてPWAを表示する」ためのAndroidのフィーチャーを、残念ながら私は一切触って来なかった背景があり、概念としてはわかるんだけど実際どんなものかよくわかってなかったので、この寝れない夜を利用してこのブログをアプリ化してみることにしました。

0. 前提

  • 私はAndroidアプリ開発はスーパー初心者で全く知識がありません。なので、初心者が手探りでAndroid StudioとかPlay Console触ってる、くらいのライトなログです。
  • そもそもPWAをアプリ化すると何がうれしいの?など戦略の部分はあまり触れません。公式情報としてはここらへん読むといいかもしれません。
  • 調べごとしながら書いてるので随時更新していくかと思います。 一旦アプリリリースできたので記事としては更新終了します。

更新


1. Bubblewrapでプロジェクトの雛形を生成

Trusted Web Activityを使ったアプリ作成は色々ツールが出揃ってきている印象で、GUIだとMicrosoftが公開しているPWABuilderがありますし、CLIだとBubblewrap(旧Llama Pack)が用意されています。PWABuilderなんかすごい簡単で、3ステップくらいでAPK吐き出します。PWAを立ち上げる軽量なAPKを生成するという単純な目的であればこういうツール類を素直にそのまま使うので十分ではないでしょうか。ただ今回はもろもろ検証するという目的で、Bubblewrapを利用してAndroidプロジェクトの雛形を吐き出してそれを使うことにします。

Bubblewrap CLIをインストール

ここまでは簡単。

対象のPWAを検証

Trusted Web Activityを利用したアプリは実際にはWebアプリが動くわけですが、激遅なUXだとアプリ化しても微妙なのでminimum quality criteriaを設けています。そこらへんを加味して事前に検証してくれるのがBubblewrap Validatorです。ちょっと試してみます。

普通にFAILしてますね。あれ、おかしいな、ちゃんとPWAなんだけどな、とLighthouse v6.0動かしてみるとなんか問題ありますね。

todo-add-alt

こちら1000年前にはなかった評価項目かと思うので愚直に対応します(こういうののためにPerfromance Budgetじゃないですけど、定期的にヘルスチェックは必要だなーとしみじみ)。
再度Validationを実施してみると...

SUCCESS🎉 これで下ごしらえはできました。ちなみにBubblewrap validatorはここらへんの実装をみると実際どんなことしてるかがわかってスッキリするかと思います。

Androidプロジェクトを生成

$ bubblewrap initしていきます。

こんな感じでWeb App Manifestを利用して対話式でプロジェクトが生成されます。簡単!

2. Android Studioを立ち上げてプロジェクトをimport

これは普通にimportすればいいです。Android本当によくわからないのですが、ちょっとどんな設定になっているのかを見ていきます。

AndroidManifest.xmlを見ると、起動時のアクションとしてcom.google.androidbrowserhelper.trusted.LauncherActivityが指定されていて、またそのIntent Filterとしてandroid:host="blog.uskay.io"android:scheme="https"android:autoVerify="true"として設定されており、httpsスキーマでのディープリンクかつDigital Asset Linkの検証までがデフォルトで準備されています。

build.gradleの中身を覗くと、なんかリソースとしてWeb App Manifestの内容を追加していて、最終的にはそこで生成されたgradleResValues.xmlに設定された値が、AndroidManifest.xml等で参照されているようみ見えます。従って、何か値を修正するとしたら、gradleをいじるか、$ bubblewrap updateするとよさそう。

特にその他生成されているActivityはなく、android-browser-helperで用意されているものをそのまま使っているようですね。BuildConfigくらいしか存在しない。デフォルトで色々用意されていて便利ですね。

todo-add-alt

3. Digital Asset Links

前述の通り、すでに色々デフォルトで設定済なのであとマストでやることと言ったらDigital Asset Linksの対応だけです。これやってないとChrome Custom Tab(またはFallback optionとして選べばおそらくWebview)で開くこととなります。

あとは署名済APK/App BundleをPlay Consoleに登録するだけ!...なんですがちょっと追加でやりたいことがあるので、もうちょっといじってみます。

4. トラッキングまわりを整理する

Trusted Web ActivityはフルフィーチャーなChromeの上で動いているだけなので、通常のウェブ向け計測は利用できます。リファラはandroid://スキーマが設定されているのでそれで通常ウェブと区別してもいいかも知れませんし、起動URLにパラメタ追加してもいいかもしれません。如何様にもできる気がします(以下はGAのリクエスト。dlはドキュメントURL、drはリファラです。)。

todo-add-alt

一方でWebviewと違い@JavascriptInterfaceアノテーションなどが使えるわけではないので、いわゆるモバイル計測プラットフォーム(AdjustTUNEAppsFlyerなど)を使うにはちょっと工夫が必要です。AppsFlyerがそこらへんのガイドを出していて大変参考になるのですが、基本Native SDKは利用できないので、一旦ウェブ側で必要なデータ全部かき集めて、Server to Serverで連携してくださいと読めます。ちょっと手順を大まかに整理すると...
  • アプリ起動時にNative側でしか収集できないデータ(たとえばAdvertising IDだったり、各SDKが発行するIDだったり)を取得し、それをTrusted Web Activityに引き渡す。
  • そのデータを利用して、Server to Serverで計測情報(コンバージョン等)を各プラットフォームに連携する。
というパターンが共通して必要な気がするので、今回は特に前者をどのように実装すればイケるのか試してみようと思います。

データ引き渡しパターン

大まかには二通りありまして、
  • 起動URLのパラメタとして連携する方法
  • Custom HTTP Request Headerとして連携する方法
かと思います。特に前者の方法はこちらでも案内されているのでBubblewrap使うのであれば一番安全かなと感じます。一方でQuery Parmeter vs HTTP Request Headerのどちらがいいか議論もあると感じていて、Query Parameterは実装が簡単なんですが、URIに付加されている情報は誰からも簡単にアクセスできてしまう上にMaximum Lengthに関しても気になる点はあります。従ってここでは後者のCustom HTTP Request Headerをどのように利用できるかをフィージビリティ検証していきたいと思います。

EXTRA_HEADERSを利用する

AndroidではIntentに対していろいろな付加情報をputExtraで追加できるようで、今回はその中のBrowser.EXTRA_HEADERSを利用したいと思います。ちょうどAppsFlyerの例にもありますが、Bubblewrap関係なく素で実装するとこんな感じになるはず。

ただ、前述したとおり、BubblewrapはLauncherActivityを利用しているので、それを活かしながらCustom Headerを追加しようとすると、そのままではうまく拡張できない気配があります。独自のQuery Parameterを設定するためにgetLaunchingUrlはOverrideできるように作られています。一方でCustom Headerに関しては、実際にputExtraしたい対象のIntentを組み立てるTrustedWebActivityIntentBuilderを生成するところが、onCreateに直接書かれているのでなんか初見ここに何かを差し込むのは厳しそうに思えてきました。なので最適解はおいておいて、ひとまずここは検証を先にすすめるという意味で、こちらをForkしてIntentに付加情報をInjectできるように作り変えてみます。
  • 明らかに共通部分と思わしき、そして実際にbuilder.build(customTabSession).getIntent()でIntentを触っている、TwaLauncherには基本手を加えない。また、builder.buildをコールしている箇所は他にもありそう。
  • 逆にLauncher Activityで一番最初にTrustedWebActivityIntentBuilderを生成する処理を、拡張可能にしてあげれば他もちゃんと動きそう。
とうことで、拡張済の独自IntentBuilderを差し込めるようにFactoryをかまし、そこでIntentだけをカスタマイズできる処理を外部注入できるようにひとまずしてみました(AndroidManifest.xmlで注入クラスを定義する感じ)。今回試してみた変更の実際のコード全容はこちら

その上で、実際にIntentを独自カスタマイズしてputExtra(Browser.EXTRA_HEADERS, customHeaders)する処理を書いて注入していきます。こちらも実際のコード全容はこちら

ちょっとハマったのが、Advertising IDを取得する処理が非同期処理しか存在しなかったので、ApplicationのonCreate時に取得するようにしたのですが、あってるのかな(なんか今の私の実装だとRace Conditinon大いにありそう)。ひとまず今回はGoogle AdsのApp Conversion Tracking APIに必要なデータを追加してみました。

動かしてみる

ちゃんと独自追加したHTTP Request Headerがついています。よかった。こちらちなみに私のAVD上で動かしているものです(Advertising IDなどもテスト環境のもの)。

todo-add-alt

署名済のAPKは、ちゃんとフルスクリーンで起動します(AVDだとスプラッシュスクリーンでないのなんでだろう?実端末だと出ます。)。


5. Play Storeに掲載してみる

審査中...(進展があればこちら更新します) 審査も通って無事公開できました。800KBくらい。
todo-add-alt

全体を通して

  • Trusted Web Activityを使ったPWAのアプリ化は、ツール郡が揃ってきていてそれなりに気軽にできるようなった印象です。
  • 一方でBubblewrap validatorにもあるとおり、前提としてPWAとパフォーマンスの基準を満たす必要があるのでやはりその対応は優先度「高」かと思います。
  • 今回はトラッキングまわりも検証してみましたが、対応策はいろいろありそうなのでそこまでブロッカーにはならないかなと感じました。
ただしそれぞれかなりライトな検証しかしてないので見落としている可能性は大いにあります。また気づいた点あれば更新していきます。

今夜は眠れるといいなぁ。


$whoami

Yusuke Utsunomiya (宇都宮 佑亮). Working on the Web Platform but mostly just a big fan of the web and its ecosystem. APAC Manager & Staff Partner Solutions Engineer @Google. Ex Systems Engineer @IBM. Opinions are my own.

Presentation

Article