前回、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では次のようになります。
注目するのは、最後の 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}&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.xml
に nav-graph
タグの設定は不要になります。
まとめ
Deep Linkはいろんな用途に使える反面、使いこなすにはそれなりに難しい感じですね。