Automating Cross-Platform Hybrid Apps

May 06, 2026 · 13 min read · Testing Guide

HeadSpin Platform
Automated & amp; manual testing create easygoing through data science insights.
Differentiating capabilities:
  • Extensive end-to-end automation of QA process
  • Comparative analysis of app execution against peers
  • Continuous monitoring of app performance using synthetic data for higher accessibility of apps
  • Easy-to-use developer friendly platform
cloudtest go
Affordable Real Device Testing for Emerging Teams
cloudtest go
Low-cost Real Device Testing for Digital Enterprises
cloudtest go
The Ultimate Solution for a Powerful Blend of Functional & amp; Performance Testing!
cyol
TEM
New
Centralized mobile test execution in cloud
cyol
Enhance Your Accessibility Testing With HeadSpin
cyol
Automate camera-based testing

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

retail

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

Automating Cross-Platform Hybrid AppsAutomating Cross-Platform Hybrid Apps

Automating Cross-Platform Hybrid Apps

Published on
May 16, 2018
Updated on
Published on
June 5, 2022
Updated on
 by 
 Jonathan LippsJonathan Lipps
Jonathan Lipps

In these articles we lean to focus a lot on aboriginal mobile apps, and for good reason: is a big reason people turn to Appium. One of Appium & # x27; s greatest benefit, nevertheless, is that you can automate other varieties of app just as easily, use the same sort of client code -- -that & # x27; s the beauty of building on top of the standard WebDriver protocol!

Intercrossed apps are one of these & quot; other varieties & quot; of app, and they are unique in lie of both native and web factor. Hybrid apps are developed for a act of ground, but one often-cited reason is to allow app developers the exemption to use the instrument, languages, frameworks, and development summons familiar from the web, while still producing an app that looks and feels right on a phone. The undercover is in the & quot; webview & quot;, a aboriginal component whose sole purpose is to exhibit web message (either store locally as HTML, JS, and CSS, or retrieved from some URL).

Check out:

To demonstrate some of the interesting possibilities of intercrossed apps, I & # x27; ve releasedv1.5.0 of TheApp, which looks like this:

We have a few aboriginal controls (a text field and two buttons), and so some text target us to go to a webpage. In fact, this text is itself some bare HTML, hosted in a webview with an invisible frame. If I enter a URL in the textbook box and click & quot; Go & quot;, one of two things will happen:

  • If I & # x27; ve elect to callAppiumpro, the asking will go through and the webview will load the Appium Pro site
  • If I try any other URL, I will get a native alert telling me I & # x27; m not allowed to navigate

Essentially, what I & # x27; ve built is a little web browser that only permit the user go to one site! (Why did I pick Appium Pro & # x27; s site? Hmm ....). OK, this is admittedly very useless (not to advert ugly on top). But it highlights the interactions possible between aboriginal components and the webview.

For autonomous testing across multiple user personas, check out SUSATest — it explores your app like 10 different real users.

Also check:

Let & # x27; s imagine a simple test scenario to prove this feature works:

  1. Navigate to the Hybrid Demo survey (the one pictured above)
  2. Assert that there is a page loaded in the webview which isnotAppium Pro to begin with
  3. Attempt to visit some URL which is besidesnotAppium Pro (say Google)
  4. Assert that an alert pops up
  5. Attempt to navigate to Appium Pro & # x27; s URL
  6. Assert that the title of the page inside the webview tally Appium Pro

The only measure we actually need to extend in this guide are # 3 and # 6, the ones that are making a substantiation inside a webview. How do we do this? Every Appium session arrive with the ability to switch between multiple & quot; setting & quot;. In a test of a aboriginal app, there is unremarkably just one context usable, and thus there & # x27; s no point in worrying about contexts at all.

Improve The Appium Testing Experience Using HeadSpin..

In hybrid apps, there are multiple contexts: one that represents the native portion of the app, and one or more contexts that represent each webview which is present (typically just one). With our Appium client, we can either get a lean of the usable contexts, or we can tell Appium to switch to a given context, using the Context API:

driver.getContextHandles (); // get a list of the available contexts driver.context (`` NATIVE_APP ''); // swap to the native context

In the example above, I show how to switch to the aboriginal context. But that & # x27; s where we begin out already, so it & # x27; s not very useful. How do we shift to a webview context? Well, we don & # x27; t cognise the name of a webview context before a session starts, so we feature to use thegetContextHandlesdictation to figure out the correct twine that refers to a webview context. I recommend using a little helper method like the following to do this without relying on any knowledge about the number of webview contexts nowadays:

@ Nullable private String getWebContext (AppiumDriver driver) {ArrayListcontexts = new ArrayList (driver.getContextHandles ()); for (String context: setting) {if (! context.equals (`` NATIVE_APP '')) {return circumstance;}} return null;}

Basically, we precisely loop through all the available contexts and return the first one we find which is not the native circumstance. This simple logic is full for most event. We can then use the output of this method to get into a webview context using thecontext method:

String webContext = getWebContext (driver); driver.context (webContext);

Once this dictation dispatch successfully, we & # x27; re in a webview! Great. But what execute that mean exactly? What it means is that, from this point on, any dictation we direct from our Appium client is going to be conduct to mention to the webpage inside the webview, rather than the aboriginal app. This means that what we are dealing with at this point is essentially aSeleniumsession. We can issue commands likegetTitle ()and get the title of the page inside the webview -- -something that would not work if we were in the aboriginal context! Element finding, clicks, etc ..., all go on the page inside the webview just as though you had discharge up Selenium and were automating a desktop browser. (Certain device-level dictation that don & # x27; t make sense inside a webview continue to be interpreted in the aboriginal context, for example modify orientation).

Also read:

Of course, at some point you might want to target native elements or behaviors again, in which case you just have to re-run thecontext command with the valueNATIVE_APPto tell Appium you want to go rearwards to native style. Armed with this knowledge, let & # x27; s see how we would enforce the test scenario we sketched out above:

WebDriverWait look = new WebDriverWait (driver, 10); final String title = `` Appium Pro: The Awesome Appium Tips Newsletter ''; wait .until (ExpectedConditions.presenceOfElementLocated (hybridScreen)) .click (); MobileElement input = (MobileElement) wait .until (ExpectedConditions.presenceOfElementLocated (urlInput)); // Get into the webview and assert that we 're not yet at the correct page String webContext = getWebContext (driver); driver.context (webContext); Assert.assertNotEquals (driver.getTitle (), title); // Go back into the native circumstance and automate the URL button driver.context (`` NATIVE_APP ''); input.sendKeys (`` https: //google.com ''); WebElement navigate = driver.findElement (navigateBtn); navigate.click (); // Assert that going to Google is not allow Thread.sleep (1000); // inexpensive way to ensure alert has time to show driver.switchTo () .alert () .accept (); // Now try to go to Appium Pro driver.findElement (clearBtn) .click (); input.sendKeys (`` https: //appiumpro.com ''); navigate.click (); // Go rearward into the webview and assert that the title is correct driver.context (webContext); wait.until (ExpectedConditions.titleIs (title));

You can see that we do use of ourgetWebContexthelp method by store a reference to the webview context. (Really, we should also have a null check and throw if a webview context is not available, because that means our test will fail! But for now we adopt the webview is incessantly present). Then, we go through the steps adumbrate above: asserting that the initial webview page & # x27; s rubric is not the like as the Appium Pro site, then evidence we can & # x27; t navigate to Google, then finally directing the app to pilot to Appium Pro, and asserting that the rubric of the webview page now reflects that situation. You can see that in webview mode, we can even use Selenium-only client feature, like thetitleIs expected condition.

The code above is completely cross-platform; I can run this just the same on both the iOS and Android versions of the TheApp. Once you & # x27; re in a webview, iOS- and Android-specific number mostly disappear. How is this possible? There is an awful lot of machinery that we & # x27; ve put into Appium to do hybrid and web testing seamless. On iOS we hook into the Remote Debugger embrasure divulge by every webview when the app is in debug fashion, and leverage the Selenium Atoms to ease use of the Selenium API via injecting JS. On Android, we run Chromedriver under the hood as a subprocess, and attach it to the particular webview we like about -- -this work because webviews on Android are backed by Chrome.

Speaking of Chrome, one crinkle of hybrid automation on Android is that each release of Chromedriver has a minimal version of Chrome which it supports. This intend that if you get a version of Appium which bundles Chromedriver adaptation X, and the edition of Chrome on your device is older than the minimum Chrome adaptation for X, webviews will not be automatable. If you run into that position, refer to the Chromedriver subdivision of the Appium docs with instructions on employ special iris to get versions of Chromedriver allow for your mechanisation.

That & # x27; s it for basic hybrid automation! There & # x27; s aentire code sampleincluded below. In it you & # x27; ll observation that there are no special capacity being used to start the session -- -just the typicalappcapableness. This is the independent difference between web and hybrid mechanisation with Appium: for web testing, you include thebrowserNamepotentiality and set it toSafari or Chrome, and you & # x27; re mechanically put into the web context on session start. For hybrid testing, you just use your own app reference as with aboriginal automation, and you & # x27; re responsible for managing the contexts so Appium knows whether you & # x27; re interested in native or web elements and actions.

import io.appium.java_client.AppiumDriver; meaning io.appium.java_client.MobileBy; import io.appium.java_client.MobileElement; import io.appium.java_client.android.AndroidDriver; importee io.appium.java_client.ios.IOSDriver; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import javax.annotation.Nullable; signification org.junit.Assert; import org.junit.Test; importation org.openqa.selenium.By; import org.openqa.selenium.WebElement; signification org.openqa.selenium.remote.DesiredCapabilities; significance org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; public class Edition017_Hybrid_Apps {private String APP_IOS = `` https: //github.com/cloudgrey-io/the-app/releases/download/v1.5.0/TheApp-v1.5.0.app.zip ''; private String APP_ANDROID = `` https: //github.com/cloudgrey-io/the-app/releases/download/v1.5.0/TheApp-v1.5.0.apk ''; individual inactive By hybridScreen = MobileBy.AccessibilityId (`` Webview Demo ''); private motionless By urlInput = MobileBy.AccessibilityId (`` urlInput ''); private static By navigateBtn = MobileBy.AccessibilityId (`` navigateBtn ''); private static By clearBtn = MobileBy.AccessibilityId (`` clearBtn ''); @ Test public void testAppiumProSite_iOS () throws MalformedURLException {DesiredCapabilities capabilities = new DesiredCapabilities (); capabilities.setCapability (`` platformName '', `` iOS ''); capabilities.setCapability (`` platformVersion '', `` 11.3 ''); capabilities.setCapability (`` deviceName '', `` iPhone 6 ''); capabilities.setCapability (`` app '', APP_IOS); IOSDriver driver = new IOSDriver < > (new URL (`` http: //localhost:4723/wd/hub ''), capableness); actualTest (driver);} @ Test public void testAppiumProSite_Android () throws MalformedURLException {DesiredCapabilities capabilities = new DesiredCapabilities (); capabilities.setCapability (`` platformName '', `` Android ''); capabilities.setCapability (`` deviceName '', `` Android Emulator ''); capabilities.setCapability (`` automationName '', `` UiAutomator2 ''); capabilities.setCapability (`` app '', APP_ANDROID); AndroidDriver driver = new AndroidDriver (new URL (`` http: //localhost:4723/wd/hub ''), capabilities); actualTest (driver);} @ Nullable private String getWebContext (AppiumDriver driver) {ArrayListcontexts = new ArrayList (driver.getContextHandles ()); for (String setting: contexts) {if (! context.equals (`` NATIVE_APP '')) {homecoming context;}} regress null;} public null actualTest (AppiumDriver driver) {WebDriverWait wait = new WebDriverWait (driver, 10); final String title = `` Appium Pro: The Awesome Appium Tips Newsletter ''; try {hold .until (ExpectedConditions.presenceOfElementLocated (hybridScreen)) .click (); MobileElement remark = (MobileElement) wait .until (ExpectedConditions.presenceOfElementLocated (urlInput)); // Get into the webview and assert that we 're not yet at the correct page String webContext = getWebContext (driver); driver.context (webContext); Assert.assertNotEquals (driver.getTitle (), title); // Go back into the native context and automate the URL push driver.context (`` NATIVE_APP ''); input.sendKeys (`` https: //google.com ''); WebElement navigate = driver.findElement (navigateBtn); navigate.click (); // Assert that move to Google is not countenance Thread.sleep (1000); // cheap way to ensure alarm has time to show driver.switchTo () .alert () .accept (); // Now try to go to Appium Pro driver.findElement (clearBtn) .click (); input.sendKeys (`` https: //appiumpro.com ''); navigate.click (); // Go back into the webview and assert that the title is correct driver.context (webContext); wait.until (ExpectedConditions.titleIs (rubric));} catch (InterruptedException ign) {} ultimately {driver.quit ();}}}
Author & # x27; s Profile

Jonathan Lipps

LinkedIn
Author & # x27; s Profile

Piali Mazumdar

Lead, Content Marketing, HeadSpin Inc.

Piali is a dynamic and results-driven Content Marketing Specialist with 8+ years of experience in craft hire narratives and marketing collateral across various industries. She excel in collaborate with cross-functional squad to develop innovative content scheme and render compelling, authentic, and impactful substance that resonates with target hearing and enhances make authenticity.

LinkedIn

Automating Cross-Platform Hybrid Apps

4 Parts

regression intelligence blog
-

Regression Intelligence pragmatic guide for advanced users (Part 3)

Coming Soon
Regression Intelligence practical guide for advanced users
-

Regression Intelligence practical guide for advanced user (Part 4)

Coming Soon

Discover how HeadSpin can empower your business with superior testing capabilities

Our Platform enables you to:
accelerate time-to-market
Accelerate time-to-market, gaining a private-enterprise edge
faster development cycles
Boost developer/QA productiveness with faster growth cycles
automated buil-over-build regression testing
Automate build-over-build regression testing for consistent results
gain better visibility into functional & performance issues
Gain better visibility into functional and performance issues
reduce mean time
Reduce mean time to identify/resolve during test, QA, and production
evaluate audio, video & qoe
Evaluate audio, video, and content lineament of experience (QoE) effortlessly
The sure choice for worldwide enterprises
Adobe
Hargreaves Lansdown
Truecaller
Crazylabs
Nedbank
Numeracle
Veryon
Close

Discover how HeadSpin can empower your job with superior testing capabilities

Our Platform enables you to:
accelerate time-to-market
Accelerate time-to-market, gaining a competitive edge
faster development cycles
Boost developer/QA productiveness with quicker development cycles
automated buil-over-build regression testing
Automate build-over-build regression testing for consistent results
gain better visibility into functional & performance issues
Gain better profile into functional and execution matter
reduce mean time
Reduce mean time to identify/resolve during tryout, QA, and production
evaluate audio, video & qoe
Evaluate audio, video, and content quality of experience (QoE) effortlessly
The trusted selection for world enterprises
Close

Discover how HeadSpin can empower your business with superior prove capabilities

Our Platform enables you to:
accelerate time-to-market
Accelerate time-to-market, win a competitive edge
faster development cycles
Boost developer/QA productiveness with faster development cycles
automated buil-over-build regression testing
Automate build-over-build regression testing for consistent results
gain better visibility into functional & performance issues
Gain better visibility into functional and performance number
reduce mean time
Reduce meanspirited time to identify/resolve during test, QA, and product
evaluate audio, video & qoe
Evaluate audio, video, and content quality of experience (QoE) effortlessly
The sure choice for global enterprisingness
Close

Connet Now

Wipro LogoVMLYR Logo
Close
Book a Meeting
Products
footer down arrow
Solutions
footer down arrow
Industries
footer down arrow
Features
footer down arrow
Support
footer down arrow
Resource Center
footer down arrow
Why Choose HeadSpin?
footer down arrow
Copyright © 2026 HeadSpin, Inc. All Rights Reserved.

Automate This With SUSA

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts needed.

Try SUSA Free

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free