Reputation: 1796
With Jetpack Navigation library (Ver 2.1.0-alpha03
at the time of writing) constructing deeplink URI's allows for the substitution of ${applicationId}
for the applications package name (it uses Context.getPackageName()
).
<fragment
android:id="@+id/screen1"
android:name="com.example.Screen1Fragment"
android:label="Screen1Fragment"
tools:layout="@layout/fragment_screen1" >
<deepLink android:id="@+id/screen1_link"
app:uri="https://${applicationId}/screen1/" />
</fragment>
By using the Navigation library the creation of intent filters is done for you.
Before Jetpack Navigation intent filters could be set by resources. Example:
<intent-filter>
<action android:name="com.example.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data
android:host="@string/app_intent_host"
android:path="/settings"
android:scheme="https"/>
</intent-filter>
I am currently working on a white label application where package name
!=
deep-link host-name
.
Without re-defining all the navigation graphs in a series of flavors can I specify the deep-link hostname?
Upvotes: 4
Views: 1157
Reputation: 1796
Jetpack Navigation library allows you to create or define your own graphs as well as destinations, but a compelling reason to use Navigation is to handle deeplinks, while having the Navigation library build the navigation back stack to the entry destination.
Jetpack uses a Gradle task to convert the deeplink URL's within your navigation graph into an intent filter in the manifest. The XML navigation graph is also read at runtime to create the Navigation graph with corresponding deeplink entries.
This can be fixed by creating a gradle task that substitutes tokens with a gradle prameter or a default.
Add a new gradle file navigation.gradle.kts
import java.io.BufferedReader
tasks.register("convertNavigation") {
doLast{
val appIntentHost: String by project
val MAGIC_TEXT = "{@string/app_intent_host}"
val DEFAULT_URL = "default.url.com"
val generatedResDir = File(buildDir, "generated/local/main/res")
val targetDir = File( generatedResDir, "navigation")
if (targetDir.exists()) {
targetDir.delete()
}
targetDir.mkdirs()
val tree = fileTree("src/main/nav/navigation")
val host: String = if (project.hasProperty("appIntentHost") && !appIntentHost.isBlank())
appIntentHost else DEFAULT_URL
println ("Replacing $MAGIC_TEXT in nav files with [$host]")
for (f in tree) {
val target = File(targetDir, f.name)
println ("Transforming ${f.name} to ${target.absolutePath}")
val writer = target.writer()
val allText = f.absoluteFile.inputStream().bufferedReader().use(BufferedReader::readText)
writer.write(allText.replace(MAGIC_TEXT, host))
writer.close()
}
}
}
Add this to your build.gradle
for the app/module where you have navigation
apply from: "navigation.gradle.kts"
gradle.projectsEvaluated {
// Modifies and copies asset nav graphs to generated
preBuild.dependsOn convertNavigation
}
android{
sourceSets {
//Location of generate navigation XML
main.assets.srcDirs += 'src/main/nav'
}
}
Move your navigation xml to src/main/nav/navigation
(eg MyApplication/app/src/main/nav/navigation
) and make deeplinks look like this
<deepLink android:id="@+id/verify_link"
app:uri="https://{@string/app_intent_host}/verify/" />
This will generate the correct manifest default.url.com
as the URL unless you run the gradle script with -PappIntentHost=customer.url.com
, in which case that get subsituted.
Hopefully this will get fixed by Google (I don't know where the open source for gradle script that does this) and this will become an invalid answer in the future. Google issue tracker
Upvotes: 2