How to Test Deep Links in Android: Three Different Options | Deep Link Testing Guide - Mobot App Testing Platform (2024)

Testing deep links in Android takes some effort, but you have all of the tools you need with ADB and Espresso. Here's how to get started.

Deep links are an important feature in mobile applications. By taking users directly to specific sections or pieces of content, they increase engagement. But, they're not easy to implement and require careful testing. If you don't make verifying deep links a part of your testing process, you risk leaving users disappointed and angry instead of engaged.

Let's look at three different options for testing deep links.

Looking to test deep links in your app? Get your first robot-powered app test free

Testing Deep Links on Android

To follow this tutorial, you'll need to install Android Studio. This tutorial works with Kotlin version 1.15.x or newer and Android SDK version 29 or newer.

We'll use a simple Kotlin Android application with two types of deep links; application links and web links. We'll very briefly look at how to implement a set of deep links and then dive right into how to test them. To focus on testing techniques, both the overall application and the links themselves are very simple. The application is based on the "Basic Activity" sample application in Android Studio.

Android applications define their links in AndroidManifest.xml. Let's start with an overview of the two types of links and how to define them in the application manifest.

Application Links

Application links use a proprietary scheme instead of the standard HTTP or HTTPS. You'll encounter them most often encountered on the device since we use them to move users between apps or application sections.

Here's a definition of an application link that uses dleg for the scheme.

 <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="www.example.com" /> <data android:scheme="dleg" /></intent-filter> 

So, Android will route links targeted to dleg://www.example.com to this application.

Web Links

Web links use http and https.

 <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="www.example.com" /> <data android:scheme="http" /> <data android:scheme="https" /></intent-filter> 

This definition looks largely the same as the previous one, except it has two scheme entries and the autoVerify="true" parameters.

If you want Android to automatically route links for your domain to your application instead of the website, you need to verify the links using one of the methods spelled out in the documentation. If you don't, Android will prompt users with an option to open the links in your app or in a web browser. Take care of this in advance, or automated tests will fail when the operating system tries to prompt a use that isn't there.

{{blog-cta}}

Application Code

The application handles deep links in MainActivity's onCreate method. This method passes the Intent to handleIntent, which verifies that it isn't carrying the default MAIN action. If it doesn't, the method passes the intent to ProcessDeepLinkIntent.

This method checks to see if the op parameter is present. If it's present, it starts a new activity. If not, it checks for the text parameter and displays its value in the main view.

  override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(binding.toolbar) val navController = findNavController(R.id.nav_host_fragment_content_main) appBarConfiguration = AppBarConfiguration(navController.graph) setupActionBarWithNavController(navController, appBarConfiguration) binding.fab.setOnClickListener { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show() } handleIntent(intent)}private fun handleIntent(intent: Intent?) { val appLinkAction: String? = intent?.action if (appLinkAction.equals("android.intent.action.MAIN").not()) { val appLinkData: Uri? = intent?.data if (appLinkData != null) { processDeepLink(appLinkData) } }} private fun processDeepLink(appLinkData: Uri?) { val opvalue = appLinkData?.getQueryParameter("op") val textValue = appLinkData?.getQueryParameter("text") if (opvalue.isNullOrBlank().not()) { startActivity(Intent(this, NewActivity::class.java)) } else if (textValue.isNullOrBlank().not()) { val textView: TextView = findViewById<TextView>(R.id.textview_first) textView.text = textValue }} 

So, we have a simple application that extracts and uses values from a deep link. A more sophisticated app might use the values of the op parameter to perform more than one action. Or, it might use a parameter to display an item for sale or send a user to a specific screen to read a message.

Let's look a how we can test these links.

Testing Deep Links With ADB

The Android Debug Bridge (ADB) makes it easy to perform ad hoc tests against deep links in the emulator or an attached Android device. With it, you call the activity manager to broadcast an intent.

The syntax for sending an intent requires eight arguments:

  • -s <device id> to select the correct device
  • shell - to send a shell command
  • am - to call the activity manager in the shell
  • start to start an activity
  • -W to wait for the activity to finish before returning
  • -a android.intent.action.VIEW to indicate a link
  • -d <link text>
  • <application package>

Here's a shell listing the available devices and then sending an application deep link to the connected emulator. Note that the URI escapes the spaces with a \ to avoid the shell trying to interpolate them as individual arguments.

  egoebelbecker@zaku:~/android-studio/bin$ adb devicesList of devices attachedemulator-5554offlineemulator-5556deviceegoebelbecker@zaku:~/android-studio/bin$ adb -s emulator-5556 shell am start -W -a android.intent.action.VIEW -d "dleg://www.example.com?text=Testing\ application\ deep\ link" com.ericgoebelbecker.deeplinkskotlinStarting: Intent { act=android.intent.action.VIEW dat=dleg://www.example.com?text=Testing application deep link pkg=com.ericgoebelbecker.deeplinkskotlin }Status: okLaunchState: UNKNOWN (-1)Activity: com.ericgoebelbecker.deeplinkskotlin/.MainActivityWaitTime: 155Complete 

Here's the result in the emulator:

How to Test Deep Links in Android: Three Different Options | Deep Link Testing Guide - Mobot App Testing Platform (1)

The application received the deep link and displayed the text for us!

Now, let's try a web link.

 egoebelbecker@zaku:~/android-studio/bin$ adb -s emulator-5556 shell am start -W -a android.intent.action.VIEW -d "https://www.example.com?text=Testing\ web\ deep\ link" com.ericgoebelbecker.deeplinkskotlinStarting: Intent { act=android.intent.action.VIEW dat=https://www.example.com/... pkg=com.ericgoebelbecker.deeplinkskotlin }Status: okLaunchState: UNKNOWN (-1)Activity: com.ericgoebelbecker.deeplinkskotlin/.MainActivityWaitTime: 211Complete 

The emulator displays the link text.

How to Test Deep Links in Android: Three Different Options | Deep Link Testing Guide - Mobot App Testing Platform (2)

ADB and the activity manager don't differentiate between application and web links, so we only need to change the link we send with the intent.

They're handy tools for verifying deep links as you're coding since you can use the shell to send links with varying parameters and make sure your code works as expected. They're also the only test tool we'll cover here that verifies the contents of your manifest file since they test your entire application instead of individual units.

But they're not well suited for automated tests since you still need to look at the emulator to check your results.

How to Test Deep Links in Android: Three Different Options | Deep Link Testing Guide - Mobot App Testing Platform (3)

Testing Deep Links With Espresso Intents

Espresso is Google's toolkit for testing Android UIs, and Espresso-Intents is an extension for verifying and stubbing Android intents. We can use this extension to ensure that our application executes the intents we expect when we send it a link.

Espresso-intents make these checks easy with the intended() method, which verifies that it saw an Intent that matches the given criteria during the test. With some simple setup, we can use it to check that the application sees the links we pass in.

When the application is sent a link with the op parameter, it initiates a new activity by creating another Intent. Here is a test of that Android application deep link:

 @RunWith(AndroidJUnit4::class)class AppDeepLinkingIntents { @Rule @JvmField val activityTestRule = ActivityTestRule(MainActivity::class.java) @Test fun deepLinkWithOpGeneratesNewActivity() { Intents.init() val intentFoo = Intent(Intent.ACTION_VIEW, Uri.parse("dleg://www.example.com?op=doit")) activityTestRule.launchActivity(intentFoo) intended( allOf( hasComponent(NewActivity::class.java.name) ) ) Intents.release() }} 

First, we need an ActivityTestRule to run the activity, so we create it on line #6.

Then, in the test method, we initialize Espression-Intents with Intents.init() on line #11, so it will capture the intent. Next, we create the intent on line #13 and pass it to ActivityTestRule.launchActivity(). This executes the test.

Finally, we use intended() on line #15 with a matcher to verify that an Intent with a NewActivity component was seen during the test.

Run this test in Android Studio:

How to Test Deep Links in Android: Three Different Options | Deep Link Testing Guide - Mobot App Testing Platform (4)

It's all green!

Testing Deep Links With ActivityScenarioRule

We still need an automated test verifying that deep links result in the UI changes we expect. For this, we can use ActivityScenarioRule and Kotlin's ability to easily access views inside a unit test.

We used ActivityTestRule in the previous test because it plays nicely with Espresso-Intents, but Google deprecated this class in an earlier version of Espresso. We're better off using ActivityScenarioRule when we can. It has a more concise syntax and, as you'll see, makes tests easy to read and write.

Here's a test for the Android application deep link:

 @RunWith(AndroidJUnit4::class)class AppDeepLinkingTest { private val intentFoo = Intent(Intent.ACTION_VIEW, Uri.parse("dleg://www.example.com?text=foo")) @get:Rule val fooRule = activityScenarioRule<MainActivity>(intentFoo) @Test fun deepLinkApplicationTextFooHasTextFoo() { val fooScenario = fooRule.scenario fooScenario.onActivity { activity -> val viewModel = activity.findViewById<TextView>(R.id.textview_first) Assert.assertEquals(viewModel.text, "foo") } }} 

On line #4, we create an Intent with the link and action required for the test.

On line #7, we create the ActivityScenarioRule and initialize it with the Intent.

Lines #11 and #12 get the ActivityScenario from the rule and execute it inside a closure. Inside the closure, we use the activity to find the TextView that should contain the text supplied by the deep link. So, we can verify that the link worked with an assertion.

Run this test in Android Studio and check the result:

How to Test Deep Links in Android: Three Different Options | Deep Link Testing Guide - Mobot App Testing Platform (5)

Like with the ADB tests, the only difference for the web links is the contents of the Intent.

  @RunWith(AndroidJUnit4::class)class HttpDeepLinkingTest { private val intentBar = Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com?text=bar")) @get:Rule val barRule = activityScenarioRule<MainActivity>(intentBar) @Test fun deepLinkWebTextBarHasTextBar() { val barScenario = barRule.scenario barScenario.onActivity { activity -> val viewModel = activity.findViewById<TextView>(R.id.textview_first) Assert.assertEquals(viewModel.text, "bar") } }} 

If you've taken care of the link verification, your tests will pass for web links, too.

Verify Your Android Deep Links

This tutorial looked at three ways to test deep links in Android. ADB makes it easy for developers to verify links as they code. Espresso has tools for ensuring the Android UI responds correctly when it's sent a link, and Espresso-Intents is useful for stubbing and verifying intents inside tests.

Android has a robust development ecosystem, with a cross-platform IDE in Android Studio and a versatile testing library in Espresso.

Challenges withTesting DeepLinks

One of the primary challenges with writing durable automated tests for deep linking is the integration of third party apps. Deep links are crucial to drive user acquisition, engagement, adoption, and referral loops, but they don't come from within your app. You'll need to test across email, SMS, QR codes, social platforms, push notifications from the lock screen, and many more scenarios. Writing durable tests for these scenarios is quite challenging, as it requires you to leave the app context.

This is where Mobot can help. Using real, mechanical robots testing on physical devices, Mobot can efficiently automate the testing of deep linking in every scenario needed. Want to see it in action?Click here to view Mobot testing deep linking using real robots.

This post was written by Eric Goebelbecker. Eric has worked in the financial markets in New York City for 25 years, developing infrastructure for market data and financial information exchange (FIX) protocol networks. He loves to talk about what makes teams effective (or not so effective!).

How to Test Deep Links in Android: Three Different Options | Deep Link Testing Guide - Mobot App Testing Platform (2024)
Top Articles
Latest Posts
Article information

Author: Rubie Ullrich

Last Updated:

Views: 5902

Rating: 4.1 / 5 (72 voted)

Reviews: 95% of readers found this page helpful

Author information

Name: Rubie Ullrich

Birthday: 1998-02-02

Address: 743 Stoltenberg Center, Genovevaville, NJ 59925-3119

Phone: +2202978377583

Job: Administration Engineer

Hobby: Surfing, Sailing, Listening to music, Web surfing, Kitesurfing, Geocaching, Backpacking

Introduction: My name is Rubie Ullrich, I am a enthusiastic, perfect, tender, vivacious, talented, famous, delightful person who loves writing and wants to share my knowledge and understanding with you.