Navigationのimplicit deep link詳細

Kenji Abe
8 min readSep 10, 2019
Photo by Jungwoo Hong on Unsplash

前回、explicit deep linkにまとめたので、今回はimplicit deep linkについてまとめておきます。

環境

  • Navigation 2.1.0

どういうときに使うのか

特定のURIへアクセスされたとき(リンクをクリックとか)、特定のFragmentに遷移させたい時に使います。

AndroidManifest.xml<intent-filter><data android:schema="..." /> などを設定して、特定のURIでActivityを起動するのと同じようなことです。

あとは、Nested Graphから別の場所に遷移したいときなどに使います。

基本的な使い方

nav_graph.xmlを次のように設定します。

<navigation>

<
fragment
android:id="@+id/first"
android:name=".FirstFragment">
</
fragment>

<
fragment
android:id="@+id/second"
android:name=".SecondFragment" >
<deepLink
android:id="@+id/deepLink"
app:uri="example.com/hoge" />

</
fragment>
</
navigation>

<deepLink>app:uri を使って設定します。 http://https:// は省略が可能になっています。
この例では、 http://example.com/hoge または https://exanmple.com/hoge のURLにアクセスしたときに、このFragmentに遷移させます。

カスタムURLスキーマを使いたい場合は、 custom://example.com/hoge みたいにすべて指定してあげる必要があります。

最後にこれを AndroidManifest.xml へ設定します。

<activity android:name=".MainActivity">
<
intent-filter>
<
action android:name="android.intent.action.MAIN" />

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

<nav-graph android:value="@navigation/nav_graph" />

</
activity>

<nav-graph> に先程のxmlを設定してあげます。

これだけで、完成です。

(optional) Auto Verifyに対応するには android:autoVerify="true" をdeeplinkタグへ追加してあげます。

app:uriの罠

app:uri に設定するにちょっとした罠があります。例えば、以下のように設定したとします。

<deepLink
android:id="@+id/deepLink"
app:uri="example.com" />

これが、最終的なAndroidManifest.xmlでは次のようになります。

AndroidManifest.xmlのMerged Manifestで確認できます

注目するのは、最後の android:path の箇所です。自動的に / が追加されています。

そのため、実際に反応するURIは https://exmaple.com/ (最後の / が重要)になります。

さらに困ったことに、Navigationでは、一致するURLを探してFragmentの遷移するのですが、 app:uri は最後の / が設定されていないため、一致するURLが見つからず、Fragmentの遷移が行われません。
startDestination のFragmentが表示される)

バグのように見えますが、どうやら仕様のようです。Issue Tracker

なので、 app:uri にドメインだけ設定する場合は、最後の / をつけておくことをおすすめします。

BackStackをNested Graph

前回の記事でも書いたのですが、deep linkでの遷移では、必ず startDestination のFragmentがBackStackへ積まれます。

また、Nested Graphについても同様で、各Nested Graphの startDestination がBackStackへ積まれることになります。

Placeholder

app:uri にPlaceholderを指定することでパラメータとして受け取ることができます。

例えば、 example.com/users/{id} と設定して、 https://example.com/users/11 で起動された場合、idを以下のように取得できます。Stringで受け取ることになります。

arguments?.getString("id")

Safe Args

PlaceholderをSafe Args対応することも可能です。通常の引数と同じように argument を設定するだけです。
この場合、受け取る型は Int になります。

<fragment>
<
deepLink
android:id="@+id/deepLink"
app:uri="example.com/users/{id}" />
<
argument
android:name="id"
app:argType="integer" />
</
fragment>

もし、URIのパラメータがIntじゃなく、文字列だった場合ですが、対象のFragmentへは遷移せず、Activityが起動するのみになっています。

注意としては、 app:uri でパラメータを受け取らないけど、 argument タグでSafe Args使ってる場合は defaultValue をつけるのを忘れようにしてください。

Query Parameter

Query ParameterにPlaceholderを使うことも可能です。

<deepLink
android:id="@+id/deepLink"
app:uri="example.com/users?id={id}&amp;name={name}" />

(Version 2.1.0) 注意ですが、指定するQuery Parameterの順番も正しい必要があります。 ?name=hoge&id=123 の順番だとマッチしないため正しく遷移してくれません。

(Version 2.2.0-alpha02) このバージョンからQuery Parameterの順番が違っても正しく遷移するようになっています。Query ParameterでPlaceholderを使うなら、こっちのバージョンを使うようにしたほうが良いと思います。(これ書いてるときは、まだalphですが…)

Navigate using URI

アプリ内の遷移もURIを使って行うことができます。例えば、Nested Nav Graphから外側のFragmentへ遷移したいときに使用します。

<deepLink
android:id="@+id/deepLink"
app:uri="sample-app://hoge/second" />

こんな感じで、deepLinkを設定しておいて、次のようにURIを指定してnavigateすれば遷移することができます。

val navController = findNavController()
navController.navigate(Uri.parse("sample-app://hoge/second"))

アプリ内の遷移しかない場合は、 AndroidManifest.xmlnav-graph タグの設定は不要になります。

まとめ

Deep Linkはいろんな用途に使える反面、使いこなすにはそれなりに難しい感じですね。

--

--

Kenji Abe

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO