Automating deeplinks with iOS real device

Hi everyone, wasn’t sure where to put this but maybe someone will find it useful.

On a real device it is not possible to simply call driver.get(“url”), doing so will open SIRI and query with “url” often resulting in a search. Instead we can take advantage of Safari’s launch parameters and pass deep link URL as argument.

Below is sample code in Java:

String deepLinkURL = "deeplink://";
//it is necessary to first kill safari 
driver.executeScript("mobile: terminateApp", ImmutableMap.of("bundleId", "com.apple.mobilesafari"));

List args = new ArrayList();
args.add("-u");
args.add(deepLinkURL);

Map<String, Object> params = new HashMap<>();
params.put("bundleId", "com.apple.mobilesafari");
params.put("arguments", args);

driver().executeScript("mobile: launchApp", params);

driver.findElementByAccessibilityId("Open").click();
4 Likes

Just a small, but important update to the previous comment.
Key arg “-u” is valid until iOS 12.2.

If you would like you tests be executable on 12.3 and up, replace it with "–U"

3 Likes

it doesn’t work for me for any of the arguments “-u” and “-U”, any ideas?

appium log: “Cannot request the screen point at NSPoint:”

do you know what other arguments can be passed to open safari in new tab appium?

This -u and -U made all the difference between ‘not able to run’ and able to run. Thank you for sharing :slight_smile:

I am still facing issues in this. I have used the above code and still, the link opens up in the browser. i am using Appium version1.22.

public void Deeplink(String Link ) {
String deepLinkURL = Link;

	((RemoteWebDriver) driver).executeScript("mobile: terminateApp", ImmutableMap.of("bundleId", "com.apple.mobilesafari"));

	List args = new ArrayList();
	args.add("-U");
	args.add(deepLinkURL);

	Map<String, Object> params = new HashMap<String, Object>();
	params.put("bundleId", "com.apple.mobilesafari");
	params.put("arguments", args);

	((RemoteWebDriver) driver).executeScript("mobile: launchApp", params);

	//driver.findElementByAccessibilityId("Open").click();
}

Any help will be highly appreciated

I use direct enter in browser url.

  1. Open Safari
  2. Enter into url input deep link value

That is not working. It must open with the application

It is working for me 2+ years.

Also to read https://appiumpro.com/editions/84-reliably-opening-deep-links-across-platforms-and-devices

Thank you, Aleksei for your quick responses. I followed the link you shared and now it is working for me.
I appreciate your support.

HI @Aleksei,
Thank you so much for the link. But using given solution i am not able to get session of safari driver as it’s giving me null pointer exception on interacting with browser.
Any help will be highly appreciated.

write your code :slight_smile: and show where it fails
and you should interact with browser like with your native app NOT like with browser.

@Aleksei,

Below is my code:
IOSDriver driver1= null;

				try {
					driver1 = new IOSDriver<IOSElement>(new URL("http://127.0.0.1:"+capabilities.getCapability("portNumber")+"/wd/hub"),
							capabilities);
				} catch (MalformedURLException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				String deepLinkURL = "MyURL";
				//it is necessary to first kill safari 
				driver1.executeScript("mobile: terminateApp", ImmutableMap.of("bundleId", "com.apple.mobilesafari"));

				List args = new ArrayList();
				args.add("-U");
				args.add(deepLinkURL);

				Map<String, Object> params = new HashMap<>();
				params.put("bundleId", "com.apple.mobilesafari");
				params.put("arguments", args);
				
				driver1.executeScript("mobile: launchApp", params); 

Till Above code its working fine and launched browser and app.After this i am trying to interact with browser.
@iOSXCUITFindBy(xpath = “//XCUIElementTypeTextField[@name=“TabBarItemTitle”]”)
public WebElement URLInput;
URLInput.sendKeys(“MyURL”);
on this line I am getting below error:
java.lang.NullPointerException
at pages.iospages.IosIntroPages.launchDeepLink(IosIntroPages.java:127)
at testcases.iosapptestcases.IosHome_CategoryAndExperinceVerification.verifyCategoryOnSeeAllPageOnAddressChangeOnDeliverySection_Dubai_23(IosHome_CategoryAndExperinceVerification.java:829)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:133)
at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:598)
at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:173)
at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:824)
at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:146)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.testng.TestRunner.privateRun(TestRunner.java:794)
at org.testng.TestRunner.run(TestRunner.java:596)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:377)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:371)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:332)
at org.testng.SuiteRunner.run(SuiteRunner.java:276)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1212)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1134)
at org.testng.TestNG.runSuites(TestNG.java:1063)
at org.testng.TestNG.run(TestNG.java:1031)
at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:115)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)

your code will not work cause of Safari issues. sad.
you need just open safari. tap on url input. enter there first time some dummy text and tap continue. then update input with correct deep link value and tap continue again. on appeared dialog to continue with your app confirm and finally your app starts with needed deep link.

see Step 2: Launch Safari and enter the deep link in the address bar in guide

1 Like

Hi @Aleksei,
Thank you so much for reply.
As mentioned in above reply i tried to launch safari and after that deep link But After starting deep link i am not able to access the app in same session.
I also have tried below two ways.
1)Using Intent: But not able to resolve intent. I have tried dependency to resolve intent but it was giving missing artifact error. below is the code which i used for intent.

 		// Create an intent object 
				    Intent intent = new Intent(Intent.ACTION_VIEW);
				// Set the data to the intent  
				    intent.setData(Uri.parse("<deep_link_url>"));
			// Start the activity 
				    driver.startActivity(intent);
//				// Verify the deep link
				    driver.getCurrentUrl().equals("<deep_link_url>");
  1. Below is the code for 2nd way:
driver.execute('mobile:deepLink',
					    {
					        url: 'theapp://login/darlene/testing123',
					        package: 'io.cloudgrey.the_app'
					    });

at ‘mobile:deepLink’ it gives me error of “Invalid character constant” and i am not able to resolve this error.
Any help on above issue is highly appreciated.

your code for Android! not iOS.

use example for both iOS and Android
-> https://www.headspin.io/blog/reliably-opening-deep-links-across-platforms-and-devices

@Aleksei Thank you so much for reply.
Yes you are right, But i have to automate deep link for both Android and iOS.
And i have tried above given example,
1)when i am launching safari on iOS it’s giving me null pointer exception error and not able to access the safari browser.
2)For Android i tried Intent and driver.execute both method but both are giving error.
a)For intent kindly let me know how to resolve it. As using below dependency appium is not able to resolve intent.
"

eu.intent
android-sdk
1.5
"
b) for driver.execute its giving me “Invalid character constant” error.

Any help related to above issue is highly appreciated.

Hello there,

I have successfully implemented solution which Aleksei recommended: https://appiumpro.com/editions/84-reliably-opening-deep-links-across-platforms-and-devices

And this solution works very fine on the local real iOS device. Thanks @Aleksei

But, problem is that when I try it execute the script on the remote real iOS device (SmartBear BitBar), OPEN in app button dialog at the top of the Safari window is not displayed. Does anyone knows why is this happening?

BitBar caps:
“capabilities”: {
“alwaysMatch”: {
“appium:useNewWDA”: true,
“appium:enableAsyncExecuteFromHttps”: true,
“appium:safariOpenLinksInBackground”: true,
“appium:waitForIdleTimeout”: 10,
“appium:appInstallStrategy”: “parallel”,
“appium:eventTimings”: true,
“appium:autoAcceptAlerts”: “true”,
“appium:bundleId”: “io.kintojoin.ride”,
“appium:automationName”: “XCUITest”,
“appium:noReset”: false,
“appium:platformName”: “iOS”,
“appium:deviceName”: “iPhone device”,
“appium:maxTypingFrequency”: “10”,
“platformName”: “iOS”,
“appium:processArguments”: “{ “args” : [“kinto_ride_dev”] }”
}
}

once again step by step.
1 you start Safari browser on phone
2 you type in input some text
3 you tap Go button

Here is issue?

What I met that with latest iOS 17 it started to predict your url and Go starts working as continue with first prediction. What is total sh…t that i did not found how disable this. But remember while human still have better AI (hope at least for few years) now simple add " " (blank symbol) to deep link text helps fix this issue.

e.g.: “your_app://openLoginScreen” -> "your_app://openLoginScreen "