Deep Linking Through a Multiple Activity Stack on Android
“Deep linking” is an important tool for launching and controlling apps in mobile computing environments, but it also raises some interesting technical challenges. In the Android environment we identified a solution that helps address the issue of “dueling activities” related to deep linking.
"Deep links" are regular hyperlinks hosted by websites or other apps that have the added ability to launch an app, rather than another website, if the device and app support it. Deep links can be very simple – simply bringing an app to the foreground when clicked – or they can be richly complex, deep linking into a particular section of an app, or directly to the detail screen of a piece of content.
The condition we're concerned with is deep-linking into an app that uses a multiple activity stack, where the root activity has no content. A classic example of this is using a launch activity to enforce an authentication strategy. Basically, your app has a launch activity that is triggered any time you launch the app, but that activity's whole purpose is to verify that the user is authenticated, and then redirect either to a login activity if they aren't or the main content activity if they are.
The issue concerns the launch mode (android:launchMode) of the activity being linked into. Most applications whose main activity uses the "standard" or "singleTop" activity launch mode will have the classic deep-link problem: any time a deep link is clicked, a second instance of your activity will open in the app that hosts the link. Then there can be two (potentially) full-fledged versions of an app running in two different tasks.
(Example of dueling activities in Android)
The way most developers work around that issue is by changing the deep-linkable activity's launch mode to "singleTask." That way, when a deep link is clicked, instead of starting your activity in the linker's task, it forces the link to be opened in the app's task, or to start a new one.
But that raises its own issue. With a "singleTask" activity, when the activity is invoked via the deep link, any activities on top of that one are destroyed. That’s fine in many situations, but when a no-content activity is set as the deep-link target, activating the link returns an app to its global starting point. The content activity is effectively overridden by the native behavior of the single task launch mode.
The solution that we’ve found success with involves introducing a new activity; one whose entire function is to intercept deep links and funnel them into your existing application stack. This new activity can be "singleTask," allowing your actual launch activity to remain "singleTop." When the new activity receives a deep-linking intent, it simply forwards it to your launch activity, and the deep link behaves as intended.
In the code, you'll need to declare your deep-link activity in your manifest, with an intent filter for handling your deep links:
Notice that this new activity does not contain the launcher-activity intent filter. For this solution to work, it's important to keep your launch activity and deep-link-receiving activity separate. If you have a launch activity that's already "singleTop," you shouldn't have to change it at all.
Now, for the activity code itself:
Notice we're forwarding intents from both onCreate() and onNewIntent(). That will handle both cases where your app is being launched from scratch, and when it's already running.
This solution is simple and effective, and requires no changes of existing app infrastructure. It maintains a single task hierarchy for applications activities, while preserving application state when launched normally, from the home screen, app drawer or recent apps tray.
This approach has been used in other contexts, but it is particularly useful for deep linking. The original approach we based this on is here.