いまさら始めるInstant App

# はじめに
この投稿は [AbemaTV Advent Calendar 2017](https://adventar.org/calendars/2216) の12/8投稿分として書いたものです。個人的な理由で遅くなってしまいましたが、読んでいただけると幸いです。また、間違いなどの指摘もぜひコメントいただければと思います。

テーマに縛りがないので、Androidエンジニアとして気になっていた`Instant App`について書いていきます。

_記事の内容は、 [potatotips #45](https://potatotips.connpass.com/event/70161/)でLTしたものです_

# Instant Appとはなんぞや
~~`Instant App`は、Android 5.0 Lollipopから追加された新機能です。~~
現在はAndroid 4.1(API 16)以降のGoogle Playサービスがインストールされている端末で動作するようです。

従来であれば、アプリはGoogle Play Storeなどかダウンロード・インストールして初めて利用可能になります。一方、`Instant App`はその名前にある通り、アプリをインストールしなくても即座に実行できます。

まだまだ普及していないので知る人ぞ知る機能のような立ち位置になってしまっていますが、これは革命的だと個人的には思っていたりします。
ブラウザでニュース読もうと思ったら**「続きはアプリで」**といったように、Web側からアプリへの導線を用意しているところをよく見かける（気がする）のですが… アプリが入ってないユーザがそのリンクを踏んでアプリをインストールして、もう一度リンクを踏みなおしてくれるかというと、たぶんしない気がします（自分もそう）

こういうシチュエーションで、`Instant App`は大いに力を発揮してくれると思っています。

## 何ができるの？
一言で表すなら、```インストール不要なアプリ```です。
というか、公式サイト（[こちら](https://developer.android.com/topic/instant-apps/index.html?hl=ja)）にも書いてありました。

```
インストール不要のAndroidネイティブアプリ
```

アプリとは言っても、これまでのインストールして利用するアプリと比較するといくつかの制約がつきます。
https://developer.android.com/topic/instant-apps/prepare.html#restricted

- Long-running background services
- Manifest-registered broadcast receivers
- Externally accessible content providers
- Re-engagement notifications
- Content providers

アプリによっては欠かせない機能が含まれている可能性があるので、既存AppのInsntant App化はよく検討する必要があると思います。

また、一番頭を悩ませる制約として、**apkサイズ**の制約があります。
Instant Appでは、機能ごとにmoduleを切って実装するので、buildすると各moduleごとにapkが吐き出されます。このapkのサイズが**4MB**以下でないといけないので、場合によっては大幅なダイエットが必須となるかもしれません...😇

## どうやって配信するの？
`Instant App`の配信は、従来のアプリの配信と同様に、Playコンソールから成果物apkを登録することで行います。詳しくは後述しますが、アプリの各機能にURLをマッピングしているので、対応するURLにAndroid端末がアクセスしようとしたタイミングで、適切なapkをロードして実行するようです。

# Road to `Build your Instant App`
Instant Appに興味が湧きましたか？
きっと難しいと思った方が多いと思いますが、そんなことはありません！
まずは小さなプロジェクトのInstant App化から始めてみましょう👍

既存のプロジェクトをInstant App化するには、ざっくり以下のような作業が必要です。

- Instant Appの開発環境を構築
- アプリの変換準備（制約への対応）
- Instant App化作業
    - featureモジュールへの機能の切りわけ
    - App Linksの設定
- Build & Deploy

自分の環境では、調べつつ作業して2h弱でした⏰
以下、手順を簡単に説明してきます。

## Instant Appsの開発環境を構築
`Instant Apps`開発を行うにあたり、SDKの導入が必要です。
そして、このSDKを導入するにはAndroid Studioを3.0以上にバージョンアップする必要があります👀

なので、まずはAndroid Studioを3.0以上のバージョンへアップデートしましょう。
そのあとで、SDKを導入していきます。

`Tools > Android > SDK Manager`からSDKマネージャーを開き、`Instant Apps Development SDK`にチェックを入れてインストールしてください。（試したときは、`1.1.0`でした。）

<img width="800" alt="adv-01.png" src="https://qiita-image-store.s3.amazonaws.com/0/20173/c8fe390e-83d8-90fd-0483-20707920bb10.png">

## アプリの変換準備（制約への対応）
Instant Apps向けにプロジェクトへ手を加える前に、プロジェクト全体のコードの修正を先に実施しておきます。

以下のような項目に対応することになると思います。

- `Runtime Permission`に対応する  
Instant Appsでは、Android 6.0から導入されたRuntime Permissionへの対応が必要です。6.0以降の端末ではRuntime Permissionでパーミンションリクエストを行うように修正しておくと後工程が楽になると思います。
- App Linksに対応する
- **Instant Appsの制約**に対応する
    - HTTP/HTTPSの双方に対応したintentフィルター
    - intentフィルターに特定のカテゴリを設定する
    - Instant Appsに対応するインストール版アプリは無料であること
    - Instant Appsで利用不可な機能をどうにかする  
    *background services/broadcast receiver/contents provider*

## Instant Apps化作業
ここからは、プロジェクトをInstant Apps対応になるよう手を加えていきます。
Instant Appsに対応したプロジェクトでは、アプリのベースとなる`base module`と、機能が組み込まれた複数の`feature module`が含まれるような構成になります。

### 既存appモジュールをbase moduleに変換
モジュールをbase module化するにあたり、変換するモジュールの`build.gradle`を修正していきます。

1.`com.android.feature`プラグインを適用
`build.gradle`の先頭にある`com.android.application`を削除し、代わりに`com.android.feature`を追加します。

<img width="466" alt="adv-02.png" src="https://qiita-image-store.s3.amazonaws.com/0/20173/b4ccc42c-1572-586a-79ef-250040de7eea.png">

2.`applicationId`を削除

一思いに消しましょう。

<img width="484" alt="adv-03.png" src="https://qiita-image-store.s3.amazonaws.com/0/20173/8ced914f-58c0-5303-7d2b-5b383f889b26.png">

3.`baseFeature`を`true`にする

作業中のモジュールは、インストール向けapk、Instant Apps向けapkのどちらも参照する、プロジェクトのベースとなるモジュールになるので、`baseFeature`を`true`にします。

<img width="260" alt="adv-04.png" src="https://qiita-image-store.s3.amazonaws.com/0/20173/dc99a130-850f-a4a9-5a5f-ce3ca49ae7cd.png">

### featureモジュールへの機能の切りわけ
今回は、インストール向けapkとInstant Apps向けapkで機能差のないプロジェクトなので、各apk向けのモジュールを生成します。

### インストールアプリ用moduleの作成
1.moduleの作成

`File > New > New Module`と選択してモジュールを新規作成します。
モジュールタイプは`Phone&Tablet module`を選択、名前は識別できればなんでもOKです👌

<img width="800" alt="adv-05.png" src="https://qiita-image-store.s3.amazonaws.com/0/20173/98fadd02-4001-2ea1-dd53-1885a7a10133.png">

2.`build.gradle`の修正

モジュールが作成できたら、`baseModule`を参照するように`build.gradle`を修正します。
`dependencies`ブロックに、次のような1行を追加します。

```build.gradle
implementation module (':base')
```
<img width="389" alt="adv-06.png" src="https://qiita-image-store.s3.amazonaws.com/0/20173/dba33b14-9d2d-533d-eb60-f39ec880efc5.png">

3.`AndroidManifest.xml`の修正

次に`AndroidManifest.xml`の修正をします。
手を加える前は、色々記述されているかと思いますが、`<manifest>`タグだけを残し、他は消します。

<img width="710" alt="adv-07.png" src="https://qiita-image-store.s3.amazonaws.com/0/20173/49fa86e9-1618-dd00-1225-199df62a9242.png">

**ここまでの作業が完了すると、インストールタイプのアプリケーションのビルドと実行ができるはずです🎉**

### Instant Apps用moduleの作成
先ほどと同様の手順で、Instant Apps用のモジュールを作成してきます。

1.moduleの作成
`File > New > New Module`と選択してモジュールを新規作成します。
モジュールタイプは`Instant App`を選択、名前は識別できればなんでもOKです👌

<img width="800" alt="adv-08.png" src="https://qiita-image-store.s3.amazonaws.com/0/20173/7f021c02-b6f6-84e3-ce53-5f40bd371b56.png">

2.`build.gradle`の修正
先ほどと同様に、`dependencies`ブロックに`baseModule`への参照を追加します。

3.`App Links`の設定
Instant Appsでは、各画面に対してURLを設定することで、URLベースでの遷移を可能にしています。
一見難しそうですが、設定をサポートする`App Links Assistant`というツールがAndroid Studioに入ってますので、そちらを活用していきます。

`Tools > App Links Assistant`でサイドバーに`App Links Assistant`が現れます。ここにある機能のうち、`URL Mapping Editor`という機能を使って、画面とURLをGUI上から紐づけてることができます。

<img width="315" alt="adv-09.png" src="https://qiita-image-store.s3.amazonaws.com/0/20173/f9e55d6b-6b3d-bba9-ce2b-56a854a0e6e3.png">

`Open URL Mapping Editor`を押すと、`URL Mapping Editor`が表示されます。
左下の方にある+マークからマッピングを新しく定義できるので、適宜設定していきましょう。

<img width="800" alt="adv-10.png" src="https://qiita-image-store.s3.amazonaws.com/0/20173/eec1f0b9-da3a-6e82-da9c-1c8bac2ffbd1.png">

上記の例では、

- `hoge.com`へアクセス  
👉`MainActivity`が起動
- `hoge.com/top`へアクセス  
👉`MainActivity`が起動
- `hoge.com/detail`へアクセス  
👉`DropItemDetailActivity`が起動

というマッピングになっています。

## Build & Deploy
あと１歩でInstant Appが起動できる状態まできています。
最後に、Debug時の実行設定をしましょう。

`Run > Edit Configuration`から実行設定を開く
左ペインで`Instant Apps`用に用意したモジュールを選択し、`Launch Options`に起動させたいURLを指定する。（マッピング設定されているURLである必要があります👀）

<img width="646" alt="adv-11.png" src="https://qiita-image-store.s3.amazonaws.com/0/20173/201c4b67-2af2-edce-8bc5-cfcb87825a21.png">

設定できたら、編集したConfigurationを選んだ状態で実行してみましょう！
無事、URLに対応した画面が立ち上がってくれば成功となります🎉

試しにホーム画面に戻って、インストールアプリ一覧から実装したアプリを探してみましょう。Instant Appで起動しただけであれば、一覧にはいないはずです。

お疲れ様でした！

# まとめ
Instant Apps、どうでしょうか。
今回は簡単なアプリケーションの移植だったので、そんなに大変ではなかったと思います。

しかし、プロダクトコードをInstant App化させるに当たって、もっとも壁になると思われるのが、**4MBのサイズ制限**です。サポートライブラリも含め色々なライブラリを導入してアプリを開発しているところがほとんどだと思いますが、ライブラリが多すぎるとそれだけで4MBを超えてしまいかねないような気がしています。ダイエットどころではありません。手術レベルの修正が必要となるのです。

勉強会では`Instant App簡単だぞ！`と言いましたが、**シンプルなアプリケーションであれば**、という補足が必要でした😥

ですが、絶対無理ということではないし、今後改良が加えられてサポートライブラリは4MBの制限にカウントされない、などとなれば道はひらけてくるかもしれないです。

今後も引き続き注視していきたいと思いますね👀