【実践】Google Play Store でPWA配信 (TWA)

先日「GooglePlayストアでPWAが配信できるようになった！」という記事が話題になっていました。

> [Google Play Store now open for Progressive Web Apps 😱](https://medium.com/@firt/google-play-store-now-open-for-progressive-web-apps-ec6f3c6ff3cc)


実態は「Chrome72で実装されたTWA (Trusted Web Activity) を使用することで、URLバー無しでPWAページを開かせるAndroidアプリを開発できるようになった」という事です。

検証がてら**実際にTWAでPWAをGooglPlayストアに公開してみた**ので手順を紹介したいと思います。

実際のAndroidプロジェクトはGitHubでも公開しています。
https://github.com/zprodev/QR-TWA

## 環境
AndroidStudioはver3.3.1を使用します。

公開するPWAはこちらのQRコードリーダーです。
https://qr.zpro.app
![pwa.gif](https://qiita-image-store.s3.amazonaws.com/0/142643/d6b021e7-bbe0-19f7-f207-fc21aa00dfaa.gif)

## 開発から公開までの手順

### 1. AndroidStudioで新規プロジェクト作成

まずAndroidStudioで新規プロジェクトを作成します。
ここでのポイントは以下2つです。

 - デフォルトActivityは不要
 - APIレベルは16以上を選択する（自分は21を選択）

### 2. TWAサポートライブラリを有効にする

この手順2と次の手順3はGitHubのcommitログも合わせて見てもらえば分かりやすいかなと思います。
https://github.com/zprodev/QR-TWA/commit/f9bcecb5f39a515948c272d00fdc671fc60431b4

Projectレベル`build.gradle`のリポジトリに[JitPack](https://jitpack.io/)を追加する。

```groovy
allprojects {
    ...
    repositories {
        ...
        maven { url "https://jitpack.io" }
    }
}
```
Moduleレベル`build.gradle`のコンパイルオプションでJava8を有効にする。

```groovy
android {
    ...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}
```

Moduleレベル`build.gradle`の依存関係にTWAサポートライブラリを追加する。

```groovy
dependencies {
    ...
    implementation 'com.github.GoogleChrome.custom-tabs-client:customtabs:3a71a75c9f'
}
```

### 3. アプリ側のTWA設定

stringリソースとして Digital Asset Links 情報を定義する。

```xml
<resources>
    ...
    <string name="asset_statements">
        [{
            \"relation\": [\"delegate_permission/common.handle_all_urls\"],
            \"target\": {
                \"namespace\": \"web\",
                \"site\": \"https://qr.zpro.app\"}
        }]
    </string>
</resources>
```

`AndroidManifest.xml`にTWAのメインActivityとDigital Asset Linksのmetaデータを追加する。

```xml
<application ... >

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

    <activity
        android:name="android.support.customtabs.trusted.LauncherActivity">

       <meta-data
           android:name="android.support.customtabs.trusted.DEFAULT_URL"
           android:value="https://qr.zpro.app" />

       <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
       </intent-filter>

       <intent-filter>
           <action android:name="android.intent.action.VIEW"/>
           <category android:name="android.intent.category.DEFAULT" />
           <category android:name="android.intent.category.BROWSABLE"/>

           <data
             android:scheme="https"
             android:host="qr.zpro.app"/>
       </intent-filter>
    </activity>
</application>
```



### 4. PWA側のTWA設定

リリースビルドに使用するKeystoreファイルからSHA256 Fingerprintを取得する。

```sh
// 取得コマンド
keytool -list -v -keystore Keystoreファイルパス -alias エイリアス名 -storepass　パスワード -keypass パスワード
```

[Digital Asset Links宣言ジェネレータ](https://developers.google.com/digital-asset-links/tools/generator)にAndroidアプリのパッケージIDとSHA256 Fingerprintを入力し、生成された文字列を`assetlinks.json`として保存する。

PWAのドメインルートに`.well-known`フォルダを作り、その中に`assetlinks.json`を配置する。

### 5. ビルドしてGooglePlayストアに登録する

アプリアイコンなど必要に応じて変更後、リリースビルドを作成してGooglePlayストアに登録します。
TWAを使うからといって特別な手続きは特にありません。

以上がTWAでPWAをGooglPlayストアに公開する手順です。

## TWAの挙動

実際に公開したアプリはこちらです。
https://play.google.com/store/apps/details?id=app.zpro.qr

アプリの起動はこんな感じです。
![twa.gif](https://qiita-image-store.s3.amazonaws.com/0/142643/415df6d2-97a3-ecc0-2204-73e4b1e52e47.gif)

PWAの起動とは若干動作が異なりますが、フルスクリーンでWebページを表示でき、ブラウザとlocalStorageを共有できている事が確認できました。

[追記]
現在配信中アプリは [TWAの挙動をPWAに寄せていく（起動編）](https://qiita.com/zprodev/items/747d875b2f290eb76ecd) で改善を加えたものになっています。

## まとめ

現状の手順や挙動から見て「GooglePlayストアでPWAが配信できるようになった！」というのはちょっと違うかなと思いますが、WebViewとChromeCustomTabsの利点を併せ持つ新たな手法でWebサイトのアプリ化を行えるようになりました。

公開する手間自体はWebView開発とさほど変わらないし、現状だとWebViewの方が扱いやすいと感じていますが、ログインが必要なWebサービスなどではセッションやストレージ共有は大きな利点だと思うので、選択肢としてアリだなと思いました。