Simon Featherstone
Simon Featherstone

Reputation: 1796

Controlling/specifing Android Jetpack Navigation deeplink hostname

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

Answers (1)

Simon Featherstone
Simon Featherstone

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

Related Questions