AndroidManifest.xml で URI の Host/Path の有無を識別して Activity を起動し分けてみた件

# 前提

架空の「スマート LED 操作用アプリ」を題材にします :iphone:

## Host の有無の識別

以下の URI が叩かれた場合にアプリ側で対応した [Activity](https://developer.android.com/reference/android/app/Activity) を直接立ち上げたいとします。

| URI | [Activity](https://developer.android.com/reference/android/app/Activity) |
|:---|:---|
| [smart-led-controller://](smart-led-controller://) | MainActivity |
| [smart-led-controller://timer](smart-led-controller://timer) | TimerActivity |

## 問題のあるコード :no_good:

``` strings.xml
<resources>
    <string name="app_name">Smart LED controller</string>

    <string name="scheme">smart-led-controller</string>
    <string name="host_timer">timer</string>
</resources>
```

``` AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.sample.smart_led_controller">

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <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="@string/scheme" />
            </intent-filter>
        </activity>

        <activity android:name=".TimerActivity">
            <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:host="@string/host_timer"
                    android:scheme="@string/scheme" />
            </intent-filter>
        </activity>
    </application>

</manifest>
```

## 問題点

[`smart-led-controller://timer`](smart-led-controller://timer) の URI が叩かれた場合に **`MainActivity`** と **`TimerActivity`** が遷移先の候補として挙がってしまいます :cry:

![Screenshot_1532802953.png](https://qiita-image-store.s3.amazonaws.com/0/6881/e9ad9c86-2e5d-887c-f196-5bcde6317cad.png)

## 対策 :hammer_pick:

**`MainActivity`** の [`<data />`](https://developer.android.com/guide/topics/manifest/data-element) に [`android:host=""`](https://developer.android.com/guide/topics/manifest/data-element#host) を追記することで [`smart-led-controller://timer`](smart-led-controller://timer) が踏まれても **`MainActivity`** は起動先の候補に挙がらなくなりました :grinning:

## 修正後のコード :ok_woman:

``` AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.sample.smart_led_controller">

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <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:host=""
                    android:scheme="@string/scheme" />
            </intent-filter>
        </activity>

        <activity android:name=".TimerActivity">
            <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:host="@string/host_timer"
                    android:scheme="@string/scheme" />
            </intent-filter>
        </activity>
    </application>
</manifest>
```

### 備考 :information_desk_person:

但し [Android Studio](https://developer.android.com/studio/) 様から「ホストを空にすることはできない」と警告を受けます :warning:

```
android:host cannot be empty.
Ensure the URL is supported by your app, to get installs and traffic to your app from Google Search.

More info: https://g.co/AppIndexing/AndroidStudio
```

## Path の有無の識別

以下の URL が叩かれた場合にアプリ側で対応した [Activity](https://developer.android.com/reference/android/app/Activity) を直接立ち上げたいとします。

| URL | [Activity](https://developer.android.com/reference/android/app/Activity) |
|:---|:---|
| [https://smart-led-controller](https://smart-led-controller) | MainActivity |
| [https://smart-led-controller/settings/wi-fi](https://smart-led-controller/settings/wi-fi) | WifiSettingActivity |

## 問題のあるコード :ng:

``` strings.xml
<resources>
    <string name="app_name">Smart LED controller</string>

    <string name="scheme_https">https</string>
    <string name="host_smart_led_controller">smart-led-controller</string>
    <string name="path_settings_wifi">/settings/wi-fi</string>
</resources>
```

``` AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.sample.smart_led_controller">

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <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:host="@string/host_smart_led_controller"
                    android:scheme="@string/scheme_https" />
            </intent-filter>
        </activity>

        <activity android:name=".WifiSettingActivity">
            <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:host="@string/host_smart_led_controller"
                    android:path="@string/path_settings_wifi"
                    android:scheme="@string/scheme_https" />
            </intent-filter>
        </activity>
    </application>
</manifest>
```

## 問題点

[`https://smart-led-controller/settings/wi-fi`](https://smart-led-controller/settings/wi-fi) の URL が叩かれた場合に **`MainActivity`** と **`WifiSettingActivity`** が遷移先の候補として挙がってしまいます :sob:

![Screenshot_1532801360.png](https://qiita-image-store.s3.amazonaws.com/0/6881/27dce3f7-5c1f-02bd-0342-82569eb733d6.png)

## 対策 :hammer_pick:

**`MainActivity`** の [`<data />`](https://developer.android.com/guide/topics/manifest/data-element) に [`android:path=""`](https://developer.android.com/guide/topics/manifest/data-element#path) を追記することで [`https://smart-led-controller/settings/wi-fi`](https://smart-led-controller/settings/wi-fi) が踏まれても **`MainActivity`** は起動先の候補に挙がらなくなりました :sparkles:

## 修正後のコード :ok:

``` AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.sample.smart_led_controller">

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <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:host="@string/host_smart_led_controller"
                    android:path=""
                    android:scheme="@string/scheme_https" />
            </intent-filter>
        </activity>

        <activity android:name=".WifiSettingActivity">
            <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:host="@string/host_smart_led_controller"
                    android:path="@string/path_settings_wifi"
                    android:scheme="@string/scheme_https" />
            </intent-filter>
        </activity>
    </application>
</manifest>
```

### 備考 :information_source:

但し [Android Studio](https://developer.android.com/studio/) 様から「パスを空にすることはできない」と警告を受けます :rotating_light:

```
android:path cannot be empty. 
Ensure the URL is supported by your app, to get installs and traffic to your app from Google Search.

More info: https://g.co/AppIndexing/AndroidStudio
```

## One more thing...

[`https://smart-led-controller/`](https://smart-led-controller/) の URL がタップされた場合にも **`MainActivity`** が遷移先の候補に挙るようにしてみます。

## 方法

**`MainActivity`** の [`<intent-filter />`](https://developer.android.com/reference/android/R.styleable#AndroidManifestIntentFilter) に [`android:path="/"`](https://developer.android.com/guide/topics/manifest/data-element#path) を含む [`<data />`](https://developer.android.com/guide/topics/manifest/data-element) 追記します :writing_hand:

## コード

``` AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.sample.smart_led_controller">

    <application
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <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:host="@string/host_smart_led_controller"
                    android:path=""
                    android:scheme="@string/scheme_https" />

                <data
                    android:host="@string/host_smart_led_controller"
                    android:path="/"
                    android:scheme="@string/scheme_https" />
            </intent-filter>
        </activity>

        <activity android:name=".WifiSettingActivity">
            <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:host="@string/host_smart_led_controller"
                    android:path="@string/path_settings_wifi"
                    android:scheme="@string/scheme_https" />
            </intent-filter>
        </activity>
    </application>
</manifest>
```

# 参考 :books:

Deep Link のテスト方法について :bulb:

- [Create Deep Links to App Content | Android Developers](https://developer.android.com/training/app-links/deep-linking#testing-filters)
  - https://qiita.com/furusin_oriver/items/f19cd72b3712e0184773