I want to create an implicit deeplink using the navigation components.
But when I start my app with the following URL:
https://my-app.com/cars/ef123-aaf33/parts
I get the following error:
java.lang.RuntimeException: Unable to start activity ComponentInfo{myapp/screens.car.CarActivity}: java.lang.IllegalStateException:
Activity screens.car.CarActivity@3b8d354 has null extras in Intent { act=android.intent.action.VIEW cat=[android.intent.category.BROWSABLE] dat=https://my-app.com/... flg=0x13008000 cmp=myapp/screens.car.CarActivity }
The intent does not have any extras, but it should contain the carUuid
defined as URL placeholder in the deeplink. The error is thrown as soon as navArgs()
is evaluated.
This is my setup:
nav_graph.xml
<fragment
android:id="@+id/fragment_parts"
android:name="myapp.screens.parts.PartsFragment"
android:label="@string/parts"
tools:layout="@layout/fragment_parts">
<deepLink
android:id="@+id/deepLink"
app:uri="my-app.com/cars/{carUuid}/parts" />
<argument
android:name="carUuid"
app:argType="string" />
</fragment>
AndroidManifest
<activity android:name=".screens.car.CarActivity" >
<nav-graph android:value="@navigation/nav_graph" />
</activity>
CarActivity
class CarActivity : AppCompatActivity() {
private val carViewModel: CarViewModel by viewModel { parametersOf(args.carUuid) }
private val args: CarActivityArgs by navArgs()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DataBindingUtil.setContentView<ActivityCarBinding>(this, R.layout.activity_car).also { binding ->
binding.lifecycleOwner = this
binding.carViewModel = carViewModel
}
}
Useful links:
Android documentation for implicit DeepLinks
---- UPDATE ----
I created a minimal sample project and found hints on what is going on/going wrong. I posted everything on the official issue tracker: https://issuetracker.google.com/issues/155690730
I got an answer from the Navigation team and a solution/workaround that is good enough for my case. More details including the Sample project can be found here
https://issuetracker.google.com/issues/155690730
WHY IS THIS HAPPENING (answer from the Google Issue tracker)
Going to a deep link destination inside of the SubActivity
is definitely possible, but at the time of handleDeepLink()
we have not built the NavDeepLink
object to be able to identify deep link variables. Furthermore, if we were somehow able to parse the URL pattern and place it as the intent extra, for the example you have given, the by navArgs()
call in SubActivity
would return a value of "alice", which is meant for the deep link destination, not it's Activity.
The reason by navArgs()
works in an Activity when you call navigate() with NavDirections is because ActivityNavigator adds the extras to the Intent that is used to start the new Activity. When you use a deep link from adb you bypass all this logic, meaning that the intent starting the activity has no extras, which is why it fails as it should.
There is probably a better approach than nested Activities for whatever your use case my be. That being said, you can make this work by adding an extra with the key name to the adb command used to launch the app from a deep link: --es "name" <"your string">.
WHAT I DO NOW
What I do now, since I have full control over the deeplink URLs, is setting the deeplink to SubActivity itself. Furthermore I give the deeplink URL also the information what destination SubActivity should set as startDestination.
This approach works just fine for me. The only drawback is that the MainActivity is also constructed in the backstack, so that the user is first taken back to this MainActivty when pressing the back button. But I can live with that :)