导航组件:使用 uri 的深度链接取决于 buildType
Navigation components : Deeplink using uri depending buildType
有什么方法可以根据 buildType 读取常量 ${deepLinkHost}
?
debug -> deepLinkUri = http://link.debug/
staging -> deepLinkUri = http://link.staging/
release -> deepLinkUri= http://link/
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_home"
app:startDestination="@id/fragment_home">
<fragment
android:id="@+id/fragment_home"
android:name="..."
tools:layout="@layout/fragment_home">
<argument
android:name="token"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
<deepLink app:uri="${deepLinkUri}/?code={token}" />
</fragment>
这之前是通过 manifestPlaceholders.deepLinkHost 在 build.gradle 上进行管理,并通过 activity 在 AndroidManifest 中进行深层链接,但是一旦 google 使用 1 Activity 到 N 个片段,我们如何使用导航组件来管理它?
目前似乎不支持开箱即用,但有一个非常简单的解决方法。
通常注册一个深link需要两步:
- 将
deepLink
添加到导航图。由于我们不能指定任何替换或 @string
资源作为 uri,我们只将主机名定义为变量:
<deepLink app:uri="http://{deepLinkHost}/?code={token}" />
。此 link 将匹配任何主机并将 deepLinkHost
作为参数传递。
- 在
AndroidManifest.xml
中注册一个 intent-filter,因此我们的 activity 实际上对深层 link 做出反应。最新的 android studio 推荐的方法是将 <nav-graph android:value="@navigation/nav_graph" />
添加到清单中,因此它会自动生成必要的 intent-filter。但是,它将注册我们的 activity 以接受任何主机的 link,这可能不是我们想要的。因此,我们不这样做,而是使用 the standard approach。基本上,我们在这里手动定义 intent-filter,而不是从导航图中自动生成它。所以我们可以像往常一样使用清单替换。
例子
- 调试 -> http://link.debug/identification?code=123
- 分期 -> http://link.staging/identification?code=123
- 发布 -> http:///link/identification?code=123
和
- 调试 -> http://link.debug/banner?id=123
- 分期 -> http://link.staging/banner?id=123
- 发布 -> http:///link/banner?id=123
build.gradle
buildTypes {
debug {
manifestPlaceholders.deepLinkUri = "http://link.debug"
}
staging {
manifestPlaceholders.deepLinkUri = "http://link.staging"
}
release {
manifestPlaceholders.deepLinkUri = "http://link"
}
}
AndroidManifest.xml
<activity
android:name=".HomeActivity">
<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="${deepLinkUri}"
android:scheme="https" />
</intent-filter>
</activity>
navigation_main.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_home"
app:startDestination="@id/fragment_home">
<fragment
android:id="@+id/fragment_home"
android:name="..."
tools:layout="@layout/fragment_home">
<argument
android:name="deepLinkUri"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
<argument
android:name="token"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
<deepLink app:uri="{deepLinkUri}/identification?code={token}" />
</fragment>
<fragment
android:id="@+id/fragment_marketing"
android:name="..."
tools:layout="@layout/fragment_marketing">
<argument
android:name="deepLinkUri"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
<argument
android:name="id"
app:argType="integer"
app:nullable="true" />
<deepLink app:uri="{deepLinkUri}/banner?id={id}" />
</fragment>
22.05.2020 更新:
从 gradle 插件版本 3.6 开始,深度 link uri 不能在方案和主机部分包含参数,这将导致 Improper use of wildcards and/or placeholders in deeplink URI host
错误。
幸运的是,可以使用通配符,因此要使该方法再次起作用,只需更改导航图文件中的 deepLink
定义:
<deepLink app:uri="{deepLinkUri}/banner?id={id}" />
到 <deepLink app:uri=".*/banner?id={id}" />
只需简单地添加 -
<deepLink app:uri=".*/{my_token}" />
对我有用!!!这也让我很惊讶它不需要任何额外的代码。
编辑 1: 但是上面的代码也用我的 app.It 从其他应用程序打开其他 URL 是 GOOD 如果您真的希望人们使用您的应用程序打开他们的 URL。但是,如果您不喜欢那样,则可以尝试下面的修复方法。
我通过简单地为我的 URL 的两个变体添加两个 deep-link 来修复它,比如 -
<deepLink
app:uri="http://www.stage.com/{token}" />
<deepLink
app:uri="http://www.production.com/{token}" />
更新 2022-03-17:
https://issuetracker.google.com/issues/36994900#comment35
修复 将在 AGP 7.3.0-alpha08。
通过此修复,AGP 支持深度 link URI 的方案、主机和路径中的清单占位符。
用法示例:
<deepLink app:uri="${scheme}://${host}/${path}" />
旧信息:
目前还没有有效的解决方案。
请为这两个问题加注星标以便更快地解决(我认为这不会有帮助,但也许...):
2022-05-27 - 简化答案
解决方案一:
可以通过以下方式实现:
<deepLink app:uri="https://.*example.com/link" />
.*
将支持任何前缀。如果您的环境不在前缀上,请将其移至该位置。
方案二:
未按预期工作 - 更好的解决方案是使用清单占位符:
build.gradle:
...
debug {
manifestPlaceholders = [scheme: "https", host: "dev.example.com"]
}
然后:
<deepLink app:uri="${scheme}://${host}/link" />
它需要 gradle 7.3.0-alpha08
或更大。它识别深层链接,但未正确处理正确的片段 (https://issuetracker.google.com/issues/36994900#comment48)。因此,如果您希望使用隐式深层链接,请暂时坚持使用解决方案 1。
有什么方法可以根据 buildType 读取常量 ${deepLinkHost}
?
debug -> deepLinkUri = http://link.debug/
staging -> deepLinkUri = http://link.staging/
release -> deepLinkUri= http://link/
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_home"
app:startDestination="@id/fragment_home">
<fragment
android:id="@+id/fragment_home"
android:name="..."
tools:layout="@layout/fragment_home">
<argument
android:name="token"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
<deepLink app:uri="${deepLinkUri}/?code={token}" />
</fragment>
这之前是通过 manifestPlaceholders.deepLinkHost 在 build.gradle 上进行管理,并通过 activity 在 AndroidManifest 中进行深层链接,但是一旦 google 使用 1 Activity 到 N 个片段,我们如何使用导航组件来管理它?
目前似乎不支持开箱即用,但有一个非常简单的解决方法。 通常注册一个深link需要两步:
- 将
deepLink
添加到导航图。由于我们不能指定任何替换或@string
资源作为 uri,我们只将主机名定义为变量:<deepLink app:uri="http://{deepLinkHost}/?code={token}" />
。此 link 将匹配任何主机并将deepLinkHost
作为参数传递。 - 在
AndroidManifest.xml
中注册一个 intent-filter,因此我们的 activity 实际上对深层 link 做出反应。最新的 android studio 推荐的方法是将<nav-graph android:value="@navigation/nav_graph" />
添加到清单中,因此它会自动生成必要的 intent-filter。但是,它将注册我们的 activity 以接受任何主机的 link,这可能不是我们想要的。因此,我们不这样做,而是使用 the standard approach。基本上,我们在这里手动定义 intent-filter,而不是从导航图中自动生成它。所以我们可以像往常一样使用清单替换。
例子
- 调试 -> http://link.debug/identification?code=123
- 分期 -> http://link.staging/identification?code=123
- 发布 -> http:///link/identification?code=123
和
- 调试 -> http://link.debug/banner?id=123
- 分期 -> http://link.staging/banner?id=123
- 发布 -> http:///link/banner?id=123
build.gradle
buildTypes {
debug {
manifestPlaceholders.deepLinkUri = "http://link.debug"
}
staging {
manifestPlaceholders.deepLinkUri = "http://link.staging"
}
release {
manifestPlaceholders.deepLinkUri = "http://link"
}
}
AndroidManifest.xml
<activity
android:name=".HomeActivity">
<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="${deepLinkUri}"
android:scheme="https" />
</intent-filter>
</activity>
navigation_main.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/navigation_home"
app:startDestination="@id/fragment_home">
<fragment
android:id="@+id/fragment_home"
android:name="..."
tools:layout="@layout/fragment_home">
<argument
android:name="deepLinkUri"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
<argument
android:name="token"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
<deepLink app:uri="{deepLinkUri}/identification?code={token}" />
</fragment>
<fragment
android:id="@+id/fragment_marketing"
android:name="..."
tools:layout="@layout/fragment_marketing">
<argument
android:name="deepLinkUri"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
<argument
android:name="id"
app:argType="integer"
app:nullable="true" />
<deepLink app:uri="{deepLinkUri}/banner?id={id}" />
</fragment>
22.05.2020 更新:
从 gradle 插件版本 3.6 开始,深度 link uri 不能在方案和主机部分包含参数,这将导致 Improper use of wildcards and/or placeholders in deeplink URI host
错误。
幸运的是,可以使用通配符,因此要使该方法再次起作用,只需更改导航图文件中的 deepLink
定义:
<deepLink app:uri="{deepLinkUri}/banner?id={id}" />
到 <deepLink app:uri=".*/banner?id={id}" />
只需简单地添加 -
<deepLink app:uri=".*/{my_token}" />
对我有用!!!这也让我很惊讶它不需要任何额外的代码。
编辑 1: 但是上面的代码也用我的 app.It 从其他应用程序打开其他 URL 是 GOOD 如果您真的希望人们使用您的应用程序打开他们的 URL。但是,如果您不喜欢那样,则可以尝试下面的修复方法。 我通过简单地为我的 URL 的两个变体添加两个 deep-link 来修复它,比如 -
<deepLink
app:uri="http://www.stage.com/{token}" />
<deepLink
app:uri="http://www.production.com/{token}" />
更新 2022-03-17:
https://issuetracker.google.com/issues/36994900#comment35
修复 将在 AGP 7.3.0-alpha08。
通过此修复,AGP 支持深度 link URI 的方案、主机和路径中的清单占位符。
用法示例:
<deepLink app:uri="${scheme}://${host}/${path}" />
旧信息:
目前还没有有效的解决方案。
请为这两个问题加注星标以便更快地解决(我认为这不会有帮助,但也许...):
2022-05-27 - 简化答案
解决方案一:
可以通过以下方式实现:
<deepLink app:uri="https://.*example.com/link" />
.*
将支持任何前缀。如果您的环境不在前缀上,请将其移至该位置。
方案二:
未按预期工作 - 更好的解决方案是使用清单占位符:
build.gradle:
...
debug {
manifestPlaceholders = [scheme: "https", host: "dev.example.com"]
}
然后:
<deepLink app:uri="${scheme}://${host}/link" />
它需要 gradle 7.3.0-alpha08
或更大。它识别深层链接,但未正确处理正确的片段 (https://issuetracker.google.com/issues/36994900#comment48)。因此,如果您希望使用隐式深层链接,请暂时坚持使用解决方案 1。