Automating deeplinks with iOS real device

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 "

Hey @Aleksei, thank you very much on your help and effort.
Unfortunately, your recommendation doesn’t help.

I’ve also tried live testing session, and check the scenario manually on remote iOS device. And also there, OPEN in app button dialog isn’t displayed. It’s looks like this is the BitBar related problem.

I’ve wrote to their support to see what we can do.

Thanks again, cheers!

But can you tap Go button on keyboard instead?

Yes @Aleksei, I can tap Go button properly. But when I tap Go button, page is just loaded in Safari and keyboard is closed. There is no OPEN in app button when test is executed on the remote real iOS device.
I have successfully done all of those steps:

  1. Start native iOS application and do “Forgot password” steps which sends email at the end.
  2. In the background via API, email reset password link is extracted which I’m 100% sure is correct.
  3. Then do next scripts, like your solution:
    final Map<String, Object> ourAppArgs = new HashMap<>();
    ourAppArgs.put("bundleId", "our.app.bundle.id") 
    
    final Map<String, Object> safariArgs = new HashMap<>();
    safariArgs.put("bundleId", "com.apple.mobilesafari");
    
    driver.executeScript("mobile: terminateApp", safariArgs);
    driver.executeScript("mobile: launchApp", safariArgs);
    
    // define all the elements related to Safari, then:
    
    urlBarOpenBtn.click();
    urlBarTxtField.sendKeys(resetPassUrl);
    goBtn.click();
    openInAppBtn.click();
    
    driver.getPageSource();
    assertEquals(RUNNING_IN_FOREGROUND.ordinal(), Integer.valueOf(driver.executeScript("mobile: queryAppState", ourAppArgs).toString()));
    // continue with the actions in our app
    

All this code works very fine on our local real iOS device. But there is only a problem with the remote real iOS device. Possibly because of the provider setup and iOS version. Because they still do not provide iOS 17, only iOS 16.6.1 as highest version.

This is how it looks on remote BitBar real iOS device:

And this is how it looks on our local real iOS device:

what you enter in:

urlBarTxtField.sendKeys(resetPassUrl);

on screenshot i see you entered valid url which shows your site and site itself triggering to open some deep link.

for example I enter text like: “my_app://deep_link_value” and i have similar screen as in example link above

I mean looks like problem not in your code but in Web/Backend/BitBar_device. Try to enter same URL manually while your app installed on remote device. You should same fail to see popUp with Open button.

Yes, the problem is with the BitBar device. Their support told me that they re-sign iOS apps when installing them on their remote devices. So, some of the functions are disabled because of the security, like Apple pay, Wallet, etc.

Anyway, your solution helped me to solve opening deep links locally. Nice job.

Thank you @Aleksei