How to Test Deep Links on Android & iOS devices

A simple guide for any deeplink tester to learn how to test Deep Links on Real Android and iOS devices rather than emulators or simulators.

Get Started free
Guide Banner Image
Home Guide How to Test Deep Links on Android & iOS devices

How to Test Deep Links on Android & iOS devices

Deeplink testing verifies deep links’ functionality within a software application or website. A deep link is a hyperlink that directs users to a specific page or content within an application rather than just the homepage.

  • The deeplink tester will check that the deep links work correctly and redirect users to the intended destination. This involves testing them across different operating systems, devices, and browsers to ensure compatibility.
  • It also involves verifying their functionality in different scenarios, such as when the app runs in the background or when the user is not logged in.

What are Deep Links?

Deep link is a technology that launches an app and opens a specific page once the user clicks a URL on a web page or another app.

  • Implementing deep links is an exciting way to enhance the user experience by seamlessly allowing users to access the specific page without interruption.
  • Deeplinks are commonly used in mobile apps, social media platforms, and e-commerce websites to provide users with a direct and efficient way to access specific content or features. As a result of this, user engagement and retention increase significantly.

Let’s understand deep links with a simple example: When searching the keyword “Floral Wallpaper” on Google, #floralwallpaper of Instagram appears as a preview among the search results.

Deep Linking Example

As the user clicks on the Search Result link, it opens the result page in the Instagram app that is already installed on the device. This is where Deep Linking comes into play, where the user gets redirected from the web search results page to the Instagram Application.

Deep Links Example on Android

The intent here is to allow the user to access the #floralwallpaper on the Instagram app seamlessly instead of opening it on the website. This enriches the overall user experience, allowing users to access the app features seamlessly.

However, considering security aspects, Deep Links are easily exploitable if not used with due diligence for authorization purposes. Sometimes these deep links contain sensitive data, and when not tested properly, they might allow a malicious app to handle the deep link instead of the legitimate app. In such scenarios, Deep Link Testing plays a crucial role in improving the overall quality and security of the product.

Let’s dive deep into Deep Links and learn how to test them!

Deep link is a URL that navigates the user from the web to a specific page in a given app. When the user clicks a deep link, Android performs either of the following actions:

  • Opens the required app in the user’s device that can handle the link if the app is already available on the device.
  • If the required app isn’t available, it opens the only app that can handle the link or opens PlayStore, from which the user can download the required app.
  • In case when multiple apps can handle the URL, it opens a dialog allowing the user to select one app from the given list of compatible apps to open the link.

Deeplink testers ensure that deeplinks are appropriately coded, redirecting users to the correct content and functioning as intended. This role is vital for applications and websites that rely on it, such as e-commerce platforms, social media apps, and news websites.

Why are Deep Links important?

Deep Linking makes any transition between web and apps hassle-free and smooth for users. Given the seamless user experience, it helps advertisers have a better chance of converting users into customers.

  • Retaining users is the key focus of deep linking.
  • It is often used for re-engaging users and is a key component of retargeting campaigns.
  • Since it gives a seamless transition from a web link to an app, deep linking minimizes the chances of users not accessing the page redirected by the campaign URL.

Building Blocks of a Deep Link

Deep Link consists of several components, just like any URL. Let’s understand the components of a deep link with an example. Consider a dummy deep link https://www.browserstack.com/test/code=abcd. It can be categorized into:

  • https – It identifies the protocol used to access the resource on the internet.
  • www.browserstack.com – It is the host, i.e. the domain name or address of the web server that is being accessed.
  • /test – The path specifies a particular page of the content.
  • code – The query parameter to extract from intents in your destination. abcd is the value of the parameter.

Types of Deep Links

Deep Links can be classified as Default, Deferred, and Contextual deep links.

1. Default Deep Links

These deep links only direct users to the required app if it’s already installed on the device. In case, where the app is not installed, the link is unable to reach the endpoint of an app, and thus an error message is displayed.

2. Deferred Deep Links

These deep links are more complex than default deep links. They can direct users to the App if it is available on the device. In case the app is not available on the device, it directs the users to Play Store or to another location, such as the app’s website for more information, and then open the original page that the user was directed to.

3. Contextual Deep Linking

Contextual deep linking involves links that ostensibly provide additional benefits. Contextual deep links are the default or deferred deep links with added parameters. Contextual deep links don’t exist independently since the other parameters are manually added. The marketers themselves can add the parameters. Such contextual deep links help in tracking the traffic source of the campaign.

How to test Deep Links on Android?

Testing Deep Links are important to ensure a high-end user experience. Functioning of Deep Links directly impacts user engagement; that is why testing has to be performed diligently.

For getting accurate results, considering real user conditions is a must. Thus, it is recommended to perform Deep Link Testing on real devices. However, buying and maintaining real devices is costly. Hence using real device cloud, like BrowserStack, can be a great way to test deep linking under real user conditions on 3000+ browser device combinations.

Following are the different ways of test deeplink Android:

Using Android Debug Bridge

By using Android Debug Bridge (ADB) shell commands one can test the deep link flow. It is used to verify if the link navigates to the correct section of your app.

Open the terminal and enter the following command:

adb shell am start -W -a android.intent.action.VIEW -d "your deep link url"

This command starts the ADB shell with the VIEW action and specifies the deep link URL to be tested.

Using Appium Driver

The below example shows two ways of testing that the logged-in experience works correctly: first by navigating the login UI with Appium, and then by using the deep linking trick described in this edition.

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileBy;
import io.appium.java_client.android.AndroidDriver;
import java.io.IOException;
import java.net.URL;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

@RunWith(JUnit4.class)
public class Appium_Deep_Linking {

private String APP_ANDROID = "https://github.com/cloudgrey-io/the-app/releases/download/v1.2.1/TheApp-v1.2.1.apk";

private String AUTH_USER = "alice";
private String AUTH_PASS = "mypassword";

@Test
public void testLoginSlowAndroid() throws IOException {
AndroidModel model = new AndroidModel();
AndroidDriver driver = new AndroidDriver(new URL("http://localhost:4723/wd/hub"), model.caps);
runStepByStepTest(driver, model);
}

private void runStepByStepTest(AppiumDriver driver, Model model) {
WebDriverWait wait = new WebDriverWait(driver, 10);

try {
wait.until(ExpectedConditions.presenceOfElementLocated(model.loginScreen)).click();
wait.until(ExpectedConditions.presenceOfElementLocated(model.username)).sendKeys(AUTH_USER);
wait.until(ExpectedConditions.presenceOfElementLocated(model.password)).sendKeys(AUTH_PASS);
wait.until(ExpectedConditions.presenceOfElementLocated(model.loginBtn)).click();
wait.until(ExpectedConditions.presenceOfElementLocated(model.getLoggedInBy(AUTH_USER)));
} finally {
driver.quit();
}
}


@Test
public void testDeepLinkForDirectNavAndroid () throws IOException {
AndroidModel model = new AndroidModel();
AndroidDriver driver = new AndroidDriver(new URL("http://localhost:4723/wd/hub"), model.caps);
runDeepLinkTest(driver, model);
}

private void runDeepLinkTest(AppiumDriver driver, Model model) {
WebDriverWait wait = new WebDriverWait(driver, 10);

try {
driver.get("theapp://login/" + AUTH_USER + "/" + AUTH_PASS);
wait.until(ExpectedConditions.presenceOfElementLocated(model.getLoggedInBy(AUTH_USER)));
} finally {
driver.quit();
}
}

private abstract class Model {
public By loginScreen = MobileBy.AccessibilityId("Login Screen");
public By loginBtn = MobileBy.AccessibilityId("loginBtn");
public By username;
public By password;

public DesiredCapabilities caps;

abstract By getLoggedInBy(String username);
}

}

private class AndroidModel extends Model {
AndroidModel() {
username = MobileBy.AccessibilityId("username");
password = MobileBy.AccessibilityId("password");

caps = new DesiredCapabilities();
caps.setCapability("platformName", "Android");
caps.setCapability("deviceName", "Android Emulator");
caps.setCapability("app", APP_ANDROID);
caps.setCapability("automationName", "UiAutomator2");
}

public By getLoggedInBy(String username) {
return By.xpath("//android.widget.TextView[@text=\"You are logged in as " + username + "\"]");
}
}
}

Test Deep Links using Appium

Using ActivityTestRule and Espresso Intent

Follow the steps mentioned below to test Deep Links:

Step 1 Start with an activity rule

@Rule public ActivityTestRule<YourAppMainActivity> mActivityRule = new ActivityTestRule<>(YourAppMainActivity.class, true, false);

Step 2 Parse the URI (Uniform Resource Identifier) from the link and return the intent

String uri = "http://your_deep_link_from_gmail"; 
private Intent getDeepLinkIntent(String uri){ 
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri))
.setPackage(getTargetContext()
.getPackageName()); 
return intent;
}

Step 3 Launch the intent using the Activity Rule

Intent intent = getDeepLinkIntent(deepLinkUri); mActivityRule.launchActivity(intent);

Here’s a sample test that captures the above steps of Deep Link Testing using ActivityTestRule and Espresso Intent

import android.support.test.espresso.intent.Intents
import android.support.test.espresso.intent.Intents.intended
import android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent
import android.support.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import android.content.Intent
import android.net.Uri

@RunWith(AndroidJUnit4::class)
class DeepLinkingTest {

@Rule
@JvmField
val activityTestRule = ActivityTestRule(MainActivity::class.java)

@Before
fun setUp() {
Intents.init()
}

@After
fun tearDown() {
Intents.release()
}

@Test
fun should_launch_secondActivity_when_deepLinkingToActivityTwo() {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("myapp://example.com?screen=activitytwo"))
activityTestRule.launchActivity(intent)
intended(hasComponent(SecondActivity::class.java!!.getName()))
}

}

How to test Deep Links on iOS?

Following is the method to test deeplink iOS devices:

Using XCUITest

Use XCUIApplication class to launch, monitor, and terminate your app in a UI Test.

  • For Launching the Application, enter the below command.
    app.launch()
  • For Terminating the Application, use the following command.
    app.terminate()
    
  • For Activating the Application, enter the following command.
    app.activate()
    
    

To perform a UI test of a Safari deeplink, it is recommended that the required app should run in the background. If any other app is launched during an ongoing UI test, it is similar to launching the required app, but with a different bundle identifier. For launching Safari, the bundle identifier “com.apple.mobilesafari” is triggered.

To launch the required app and switch back to Safari right after, run the following code:

func testDeeplinkFromSafari() {
let app = XCUIApplication()
app.launch()
let safari = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari")
safari.launch()
}

For deeplinking back to the app, Safari has to be controlled similar to any regular UI test. This can be done in three steps:

  • identify the address bar,
  • type the deep link URL,
  • click on the “Go” button.

Ideally, Safari will deeplink back to the required app, depicting that the deeplink logic in the app is working as expected.

func testDeeplinkFromSafari() {
// Launch our app
let app = XCUIApplication()
app.launch()
// Launch Safari and deeplink back to our app
openFromSafari("swiftrocks://profile")
// Make sure Safari properly switched back to our app before asserting
XCTAssert(app.wait(for: .runningForeground, timeout: 5))
// Assert that the deeplink worked by checking if we're in the "Profile" screen
XCTAssertTrue(app.navigationBars["Profile"].exists)
}

private func openFromSafari(_ urlString: String) {
let safari = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari")
safari.launch()
// Make sure Safari is really running before asserting
XCTAssert(safari.wait(for: .runningForeground, timeout: 5))
// Type the deeplink and execute it
let firstLaunchContinueButton = safari.buttons["Continue"]
if firstLaunchContinueButton.exists {
firstLaunchContinueButton.tap()
}
safari.buttons["URL"].tap()
let keyboardTutorialButton = safari.buttons["Continue"]
if keyboardTutorialButton.exists {
keyboardTutorialButton.tap()
}
safari.typeText(urlString)
safari.buttons["Go"].tap()
_ = confirmationButton.waitForExistence(timeout: 2)
if confirmationButton.exists {
confirmationButton.tap()
}
}

It is best to add the additional wait (for: .runningForeground) assertion for safety. Inserting additional wait allows checking whether the app switching worked before the attempt to assert. If it fails, then it is evident that the failure is because the app failed to switch, and not due to something not being present in the UI of the app.

Testing Deep Links on Real Device Cloud

When testing deep linking on Real Devices, deeplink testers can decipher the issues that could cause interruptions or altered behavior of the deep link. Testing on BrowserStack’s real device cloud includes all the real user conditions while performing tests. Thus, allowing developers to test on 3500+ browser-device combinations for cross-compatibility testing.

  • BrowserStack App Automate offers cloud-based access to the latest and legacy devices (Android, iOS, and Windows) installed with real operating systems.
  • App Automate also requires no additional setup, helping testers save precious time and meet their deadlines much faster.

Since users demand high-functioning and engaging campaigns, deep link testing is a requirement before releasing any campaign. By running deep link tests on real Android devices, deeplink testers can ensure that apps work as expected in real user conditions. Run as many tests as possible on real Android devices to offer a consistently optimal user experience.

Tags
Android iOS Mobile App Testing