How to Switch Between Native App and Safari : Appium iOS Automation
When automating iOS applications with Appium, you may encounter scenarios where an action within your app opens a web page in Safari, pushing your iOS app to the background. In such cases, the challenge is to automate the web process and then seamlessly switch back to your iOS app to continue the automation from where it left off.
Appium does not offer a direct method to handle this scenario natively, which necessitates a manual approach. This involves managing the transition between the iOS app and Safari manually by terminating and reinitializing driver sessions. In this article, we'll guide you through this process using Selenium WebDriver and demonstrate how to automate the entire workflow effectively.
Understanding the Automation Flow
1. Starting with the iOS App: The process begins by initializing an IOSDriver, which controls the automation within your native iOS app. You can perform any required actions, such as interacting with UI elements, until the point where the app triggers the opening of Safari.
2. Transitioning to the Web Process: When an action in your app opens Safari, the iOS app goes into the background. At this point, you need to switch your automation focus to the web process. This is done by terminating the IOSDriver session and starting a new session using WebDriver configured for Safari.
3. Automating in Safari: Once the WebDriver is initialized, you can automate interactions within the web page opened in Safari. This could include clicking buttons, filling out forms, or any other required tasks.
4. Returning to the Native App: After completing the automation in Safari, the next step is to terminate the WebDriver session and reinitialize the IOSDriver. This allows you to return to your native app and continue the automation from where it was paused, ensuring a smooth transition back to the app environment.
5. Final Cleanup: As a best practice, both the IOSDriver and WebDriver sessions should be terminated at the end of your test to avoid any lingering sessions that might affect future tests.
领英推荐
Code Snippet
Here is a complete code snippet illustrating the process:
import io.appium.java_client.ios.IOSDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.io.IOException;
import java.net.URL;
public class AppToSafariTest {
private static IOSDriver iosDriver;
private static WebDriver safariDriver;
private final By safariElement = By.id("safariElement");
private final By loginBtn = By.xpath("native_element1");
private final By menuIcon = By.xpath("native_element2");
@BeforeTest
public static void setUp() throws IOException {
// Initial setup for iOS driver
startIOSDriver();
}
public static void startIOSDriver() throws IOException {
// Set up iOSDriver with required capabilities
DesiredCapabilities appCaps = new DesiredCapabilities();
appCaps.setCapability("platformName", "iOS");
appCaps.setCapability("platformVersion", "Your_Version");
appCaps.setCapability("deviceName", "Your_Name");
appCaps.setCapability("udid", "Your_UDID");
appCaps.setCapability("bundleId", "Your_Bundle_ID");
appCaps.setCapability("xcodeOrgId", "Your_Org_ID");
appCaps.setCapability("xcodeSigningId", "Your_Signing_ID");
appCaps.setCapability("appium:noReset", true);
appCaps.setCapability("appium:automationName", "XCUITest");
iosDriver = new IOSDriver(new URL("https://127.0.0.1:4723/wd/hub"), appCaps);
}
private void setUpSafariDriver() throws IOException {
// Set up SafariDriver with required capabilities
DesiredCapabilities safariCaps = new DesiredCapabilities();
safariCaps.setCapability("platformName", "iOS");
safariCaps.setCapability("platformVersion", "Your_Version");
safariCaps.setCapability("deviceName", "Your_Name");
safariCaps.setCapability("udid", "Your_UDID");
safariCaps.setCapability("xcodeOrgId", "Your_Org_ID");
safariCaps.setCapability("xcodeSigningId", "Your_ID");
safariCaps.setCapability("appium:noReset", true);
safariCaps.setCapability("appium:automationName", "XCUITest");
safariCaps.setCapability("appium:includeSafariInWebviews", true);
safariCaps.setCapability("browserName", "safari");
safariDriver = new IOSDriver(new URL("https://127.0.0.1:4723/wd/hub"), safariCaps);
}
@Test
public void testAppToSafariAndBack() throws IOException {
// Perform some actions in the iOS app
try {
iosDriver.findElement(loginBtn).click();
} catch (Exception e) {
throw new AssertionError("Element not clickable: " + loginBtn, e);
}
// Stop the current iOS driver session before starting Safari
if (iosDriver != null) {
iosDriver.quit();
}
// Initialize Safari driver session
setUpSafariDriver();
// Perform actions in Safari
try {
safariDriver.findElement(safariElement).click();
} catch (Exception e) {
throw new AssertionError("Element not found: " + safariElement, e);
}
// Tear down Safari driver session
if (safariDriver != null) {
safariDriver.quit();
}
// Restart iOS driver session
startIOSDriver();
// Continue with the app actions
try {
iosDriver.findElement(menuIcon).click();
} catch (Exception e) {
throw new AssertionError("Element not clickable: " + menuIcon, e);
}
}
@AfterTest
public static void tearDown() {
if (iosDriver != null) {
iosDriver.quit();
}
if (safariDriver != null) {
safariDriver.quit();
}
}
}
Key Considerations:
safariCaps.setCapability("bundleId", "com.apple.mobilesafari");
safariDriver.get("https://www.dhirubhai.net");
Conclusion:
Automating iOS apps that interact with Safari introduces complexity due to the need to switch contexts and manage multiple driver sessions. While Appium doesn’t provide a direct way to handle this scenario, by following the steps outlined above, you can effectively automate workflows that span both native apps and web processes on iOS. This method ensures that you can resume your automation in the native app right where you left off, maintaining the continuity of your test flow.