Edition 108

Working with iOS App Home Screen Actions

Home screen actions

iOS apps can register special shortcut actions that the app users can take from the home screen app icon itself. These actions are called Home Screen Quick Actions, and provide a handy way to jump straight into a task in an iOS app without navigating through the initial app views.

The way that a user accesses these actions is by performing a "tap and hold" on the app icon, and then choosing one of the options from the context menu which appears. With Appium's XCUITest driver, nothing prevents us from automating the home screen itself, so we can easily open up these shortcut actions with Appium, the same way a user would. Thankfully, iOS puts helpful accessibility IDs on the home screen icons as well as the action buttons themselves. Let's walk through an example of how we'd implement the flow shown in the animated gif above: triggering the "New Reminder" action of the Reminders app.

First, we need an Appium session. It doesn't really matter what app we choose to launch, since we're going to immediately close it and get to the home screen. We could choose, for example, to launch the Reminders app, to remain thematically consistent:

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("platformName", "iOS");
capabilities.setCapability("platformVersion", "13.3");
capabilities.setCapability("deviceName", "iPhone 11");
capabilities.setCapability("app", "com.apple.reminders");
driver = new IOSDriver<WebElement>(new URL("http://localhost:4723/wd/hub"), capabilities);

Now, we need to get back to the home screen. There are a few ways to do this, but I chose the way which should be most bullet-proof, which is the pressButton mobile method:

ImmutableMap<String, String> pressHome = ImmutableMap.of("name", "home");
driver.executeScript("mobile: pressButton", pressHome);
driver.executeScript("mobile: pressButton", pressHome);

I call this method twice, because we're not necessarily guaranteed to end up on the first page of the home screen. To be more intelligent about it, we'd probably want to put this in a loop and simply call it until we wind up on the screen with the Reminders app (because maybe the user put it on a different screen, as well). Next, we find the icon itself and tap and hold it:

// find the reminders icon and long-press it
By REMINDER_ICON = By.xpath("//*[@name='Home screen icons']//*[@name='Reminders']");
WebElement homeIcon = wait.until(ExpectedConditions.presenceOfElementLocated(REMINDER_ICON));
driver.executeScript("mobile: touchAndHold", ImmutableMap.of(
    "element", ((RemoteWebElement)homeIcon).getId(),
    "duration", 2.0
));

As you can see, rather than constructing a typical Action sequence for this, we take advantage of the fact that we know we're on iOS, and use the iOS-specific mobile: touchAndHold method, to make sure that the OS recognizes our intent. Notice also that the icon we've chosen is qualified via a more complex XPath query. This is because in the case of iPadOS, we might have two instances of the icon on the screen---one in the main area, and one in the multitasking dock.

By ADD_REMINDER = MobileBy.AccessibilityId("New in Reminders");
By LISTS = MobileBy.AccessibilityId("Lists");

// now find the home action using the appropriate accessibility id
wait.until(ExpectedConditions.presenceOfElementLocated(ADD_REMINDER)).click();

// prove we opened up the reminders app to the view where we can add a reminder
wait.until(ExpectedConditions.presenceOfElementLocated(LISTS));

In the last section of our test, above, we actually tap on the quick action text which was uncovered by our long tap. Then, we look for an element in the Reminders app that we know only shows up when we've gotten directly to the action (this is a screen which is not the typical initial screen of the app).

That's it! Nothing magic to it--just using Appium to script out exactly the behavior of a regular old human user.

As always, you can check out the code for this example in the context of a working project at the Appium Pro repo.