PWAをTWAでGoogle Play Storeに配信してみた

プログラミング 2020年1月15日

関連:vue-cli 3.0で始めるPWAとVue.jsのconfig周り

僕が趣味で作っている、リンクやTwitterの投稿などを素敵にまとめられるWebアプリのCullet | カレットを、Google Play Storeで公開しました!

Google Play Storeはこちら

そこで今回は、このリリースにあたり利用した新技術、TWA (Trusted Web Activity:トラステッド ウェブ アクティビティ)という、PWA (Progressive Web App)をGoogle Play Storeに配信するために便利なActivityの使い方と、実際のリリースまでの過程を紹介したいと思います。

Trusted Web Activity (TWA) とは

TWAは、PWA (Progressive Web Apps) をAndroidで簡単にリリースするために提供されているモジュールです。また、ここではPWAの説明は割愛させていただきます。

動作環境はChrome 72+ということで、ある程度モダンなAndroid環境を利用しているユーザが対象になりますが、なんといってもKotlinやJavaを知らなくても簡単に利用できるのが最高ですね。

また、細かいところだと、ChromeブラウザとlocalStorageなどを共有できるので、セッション情報をそのまま引き継いで利用できるのも非常に嬉しいポイントです。

TWAが提供される以前は、Webアプリを簡単にネイティブで提供する方法として、WebViewが広く用いられていましたが、これはある程度Android開発ができる人でないと少し難しかったことや、前述のlocalStorageのスコープが異なることが多少なりのネックでした。

ここでこのTWAの登場は、ネイティブアプリの開発コストをかなり下げ、開発体験をより良いものにしてくれることは間違い無いでしょう。

前書きはともかく、早速TWAのお話に移りましょう。

1. 用意するもの

  • Android Studio

インスコしましょう

0. めちゃくちゃハマったやつ

まず始めに、このTWAでのアプリ作成にあたり、日本語も含め様々な記事を参考にさせていただきました。
ただ、そのほとんどがcom.github.GoogleChrome.custom-tabs-client:customtabsを利用しているサンプルで、これが最新のAndroid Studioでのプロジェクト作成からだと上手く動かないことが発生しました。

A. custom-tabs-clientでエラー

以下のエラーが発生。

java.lang.IllegalAccessError: Method 'android.os.Bundle android.support.customtabs.CustomTabColorSchemeParams.toBundle()' is inaccessible to class 'androidx.browser.customtabs.CustomTabsIntent$Builder' (declaration of 'androidx.browser.customtabs.CustomTabsIntent$Builder' appears in hoge.apk)

これはAndroidXを利用している際に起こるものです。

公式を見てみると、com.google.androidbrowserhelper:androidbrowserhelperを利用するサンプルに変わっており、custom-tabs-clientGitHubを見てみても、AndroidXの利用の際にクラッシュするバグが既知のものとして記載があり、Android Browser Helperの利用を公式に推奨しているため、本記事ではこちらを例に実装します。やはり公式は偉大ですね(つい先日までcustom-tabs-clientだった気がするが)。

B. PWAを署名するフィンガープリントが違う

これは後の手順で紹介しますが、手元で作るフィンガープリントはAPKアップロード用のものとして利用するため、PWAの署名に用いるのは、コンソール上でGoogleが作成するものを用いる必要があります。

2. プロジェクト作成

まずはAndroid Studioで新規プロジェクトを作成します。Activityは無しで大丈夫です。

Screen-Shot-2020-01-15-at-21.15.12

そのまま、お好きなアプリ名/パスでプロジェクトを作成します。

3. ファイル編集

そして、TWAで実装すべく変えるファイルは以下です。

  • build.gradle (プロジェクトルート)
  • build.gradle (app以下)
  • AndroidManifest.xml
  • res/strings.xml
  • res/styles.xml
  • アプリアイコン(画像設定で自動生成、後述)

たったこれだけです!

さあ、これらを編集していきます。

build.gradle(プロジェクトルート)

allprojects {
    repositories {
        google()
        jcenter()
        maven { url "https://jitpack.io" }  // この一行を追加
    }
}

build.gradle(app以下)

...
    buildTypes {
        release {
            minifyEnabled true  // false -> trueに変更
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    // ここから
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    // ここまでを追加
...


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.core:core-ktx:1.1.0'
    implementation 'androidx.browser:browser:1.2.0'  // これと
    implementation 'com.google.androidbrowserhelper:androidbrowserhelper:1.0.0'  // これを追加
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

res/styles.xml

    <!-- DarkActionBar -> NoActionBarに変更 -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

res/strings.xml

    <string name="app_name">Cullet</string>
    <!-- 以下を追加、siteは各自書き換え -->
    <string name="asset_statements">
        [{
            \"relation\": [\"delegate_permission/common.handle_all_urls\"],
            \"target\": {
                \"namespace\": \"web\",
                \"site\": \"https://app.cullet.me\"}
        }]
    </string>

AndroidManifest.xml


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">


        <!-- ここから下を追加 -->

        <meta-data
            android:name="asset_statements"
            android:resource="@string/asset_statements" />

        <activity
            android:name="com.google.androidbrowserhelper.trusted.LauncherActivity">

            <!-- Edit android:value to change the url opened by the TWA -->
            <!-- valueは各自書き換え -->
            <meta-data
                android:name="android.support.customtabs.trusted.DEFAULT_URL"
                android:value="https://app.cullet.me" />

            <!-- This intent-filter adds the TWA to the Android Launcher -->
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <!--
              This intent-filter allows the TWA to handle Intents to open
              app.cullet.me.
            -->
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE"/>

                <!-- Edit android:host to handle links to the target URL-->
                <!-- ここも各自書き換え -->
                <data
                    android:scheme="https"
                    android:host="app.cullet.me"/>
            </intent-filter>
        </activity>
    </application>

はい、編集はたったこれだけです!

あとは、File -> New -> Image Asset -> Source Assetから、自前の画像を設定して、アイコンをビルドするだけで、実装に関しては完了です。

4. ビルド

Build -> Generate Signed Bundle / APKを選択し、Android App Bundle (aab)を選択します。

Screen-Shot-2020-01-15-at-21.42.02

そして、ここでKey storeなどを選択するのですが、まだ作成してない方は以下が参考になります。

Android Studioでアプリ公開用KeyStoreを作成して本番ビルドする

作成を終えたら、releaseを選択して完了を押します。少し時間を置いて、releaseディレクトリに.aabが生成され、これがAPKなどを同梱した、ストアにアップロードするファイルになります。

5. ストアに登録

それでは、作成したアプリを登録しましょう。

こちらからPlay Consoleにログインし、アプリを作成します(プロジェクト作成にあたる)。

作成したアプリのメニューに、いくつかチェック項目があると思います。

Screen-Shot-2020-01-15-at-21.51.31-1

アプリをリリースするためにはこれらは全て完了する必要があるため、以下から先に埋めてしまいます。

  • ストアの掲載情報
  • コンテンツのレーティング
  • アプリのコンテンツ
  • 価格と配布

上記が完了したら、

  • アプリのリリース

をクリックします。

アプリの内部リリース

いきなりたくさんの項目が並びますが、この中の「内部テスト版トラック -> 管理 -> リリースを作成」と進みます。すると以下の画面になります。

Screen-Shot-2020-01-15-at-21.56.35

この「次へ」ボタンを押して、アプリの配信時に利用する署名用の鍵を自動生成します。完了すると、左のメニューに「アプリの署名」という項目が追加されているはずです。ここも後でアクセスするので覚えておきます。

さあ、画面を見ると「追加するAndroid App BundleとAPK」でファイルが選択できるようになっているため、先ほどのaabファイルをアップロードします。

あとは、必要な情報を入力して登録を完了します。

アプリの署名

ここで、一旦別の作業に移ります。

それは、先ほど生成した「アプリ署名鍵のフィンガープリント」で、Webに配信中のPWAに登録する作業です。

これにより、このアプリが呼び出すPWAはこのアプリが信頼していることを証明するんですね。これがTrusted Web Activityたる所以ですね。

左メニューから「アプリの署名」を選択してください。

Screen-Shot-2020-01-15-at-22.08.43

ここからはPWA側の作業になります。
まず、上記のうち、「SHA-256」のものをコピーします。
そして、digital-asset-links generatorにアクセスして、フィンガープリントとその他の情報を入力し、asset linksを生成します。

こんなん

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target" : { "namespace": "android_app", "package_name": "net.maytry.cullet.android",
    "sha256_cert_fingerprints": ["20:41:D0:E5:83:DA:43:01:15:09:52:DC:8F:9B:13:F9:64:09:5A:71:18:B0:89:E0:78:E5:92:13:A9:39:23:2C"] }
}]

このasset linksを.well-known/assetlinks.jsonとしてファイル生成します。そして、この.well-knownディレクトリを、PWAをホスティングしているルートに配置して配信します。

これが、前述のPWAを信頼するための手順になります。

アプリの確認

それでは、アプリを確認してみましょう。
リリース管理から、内部テスト版を見てみると、「オプトインURL」というものが見つかると思います。ここから、テスト用のアプリをインストールして、PWAがAndroidアプリとして利用できるのを確認できます。

6. リリース

ここからはもはや詳しい説明は不要かと思います。アプリがきちんと動いていれば、製品版まで上げる申請をしましょう!

無事、審査をクリアすれば、晴れてPWAをAndroidアプリとしてリリースできます!!

CulletのAndroidアプリ

7. まとめ

TWAを調べ始めてから、リリース手順で少々苦労しましたが、無事アプリをストア配信できて良かったです。
つまづきポイント含め、今回の手順が助けになれば幸いです!あ、ちなみにCulletはVue.jsで作成していますよ!笑

それでは、良いPWAライフを!

slont

金融ベンチャーでWebエンジニア

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.