进阶之Hybrid

Hybrid应用,简而言之就是指Native应用里内嵌了WebView的应用。此类应用从14年开始普遍流行,从技术发展和业务契合度的角度来看,Hybrid带来了许多好处和变化,比如使App本身更加轻便,使许多热更技术变得可行等等。但这也给我们做App的自动化带了许多难度和瓶颈。

在Appium出现之前,能实现Hybrid自动化的框架并不多。而Selendroid就是其中一个。

而Appium所应用到的技术,其中一项也正是包含了Selendroid模式。

Appium下的Hybrid解决方案

  • 1、基于Selendroid模式
  • 2、基于UiAutomator + Chromedriver模式

这两种模式各有优劣:

Selendroid模式

  • 支持Android2.3+
  • 支持Hybrid自动化
  • 运行速度快
  • 无法使用许多手势API
  • apk包需要重签名
  • 无法跨进程

Appium模式

  • 支持Android4.4以上设备
  • 支持Hybrid自动化
  • 可跨进程
  • apk包无需重签名
  • 源码中webview必须为debug模式(真机)

很明显,我们从以上两个分析可以看出,Appium模式其实是更加完善,对于运行稳定性和拓展性优势是要比较明显的。目前的Android市场份额,已经逐渐向高端转化,不出半年,也会变成4.4~6.0的天下了。所以,这个模式正在从劣势变为优势。

但是上面提到的webview必须为debug模式是什么意思呢?

基于UIAutomator+Chromedriver的实践

使用chromedriver来做hybrid的自动化我们有几个前提条件必须解决:

  • 1、准备好Android4.4或以上的手机;
  • 2、将Webview设置为debug模式;
    • 设置方法:在Android SDK API>=19的情况下,在源码中添加webview.setWebContentsDebuggingEnabled(true)这一段代码即可。(如果使用的是模拟器,则无需修改源码)

Android混合应用自动化的关键API

实际上,Appium模式下,实现混合应用的自动化的原理很简单,Native部分走UIAutomator,Webview部分走Chromedriver,两者结合混搭,从而实现Hybrid的自动化。

那我们到底如何做到在UIAutomatorChromedriver之间灵活地游走呢?

除了准备工作要做好,还有几个关键的概念你需要清楚:

  • context
  • window_handle(一般很少用到)

我们通过切换当前context对象,来让Appium认识自己当前处于哪一个状态里面,对于webviewcontext对象,可能会打开多个网页,那我们还需要通过切换window_handle对象来让Chromedriver认识自己当前是打开的哪个页面。

那么,刚刚提到的两个概念,就是我们学习的重点。

解读Sample-Code

Talk is very cheap。 相信看完上面的东西,许多同学还是一头雾水。 还是从看源码解释要来得清楚一点。

我们从sample-code-androidWebViewTest.java可以看到:


public class AndroidWebViewTest {
    private AppiumDriver<WebElement> driver;

    @Before
    public void setUp() throws Exception {
        // set up appium
        File classpathRoot = new File(System.getProperty("user.dir"));
        File app = new File(classpathRoot, "../../../apps/selendroid-test-app.apk");
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability("deviceName","Android Emulator");

        //automationName必须为Appium,或者该参数不填
        capabilities.setCapability("automationName","Appium");
        capabilities.setCapability("app", app.getAbsolutePath());
        capabilities.setCapability("appPackage", "io.selendroid.testapp");
        capabilities.setCapability("appActivity", ".HomeScreenActivity");
        driver = new AndroidDriver<WebElement>(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
    }
    @After
    public void tearDown() throws Exception {
        driver.quit();
    }

    @Test
    public void webView() throws InterruptedException {
        WebElement button = driver.findElement(By.id("buttonStartWebview"));
        button.click();
        Thread.sleep(6000);

        //获取当前页面的所有Context对象,其中就会包含Native和Webview的对象。
        Set<String> contextNames = driver.getContextHandles();
        for (String contextName : contextNames) {
          System.out.println(contextName);

          //遍历获取下来的context对象,若发现context对象包含WEBVIEW字样的时候,就切换到该对象下
          if (contextName.contains("WEBVIEW")){
            driver.context(contextName);
          }
        }
        //然后就是Webview中的操作,webview下的自动化定位方式与Selenium中web的定位是一样的。
        WebElement inputField = driver.findElement(By.id("name_input"));
        inputField.sendKeys("Some name");
        inputField.submit();
    }

}

我在上面标注了4个关键的注释,请认真阅读。

其中,相比于单纯的Native测试,Hybrid测试会多两道工序,那就是:

  • 1、获取当前contexts对象
  • 2、切换到webview的context对象下

接下来后续的操作都是跟Native下相差无几。

注意点

  • 当我们在Webview下操作完毕了以后,若想要操作Native下的元素,则需要重新切换context对象到Native下,就跟你切换到webview下是一样的。

App中WebView元素的定位方式

有同学会问,Native的所有元素都可以通过uiautomatorviewer获取到,那webview里的元素我们有办法或者有工具能够帮助我们定位吗?

答案肯定是有的。

那就是chrome浏览器的inspector

使用方法:

  • 1、手机连接上电脑,并打开App,打开需要定位的Webview的页面
  • 2、电脑上打开Chrome,地址栏输入chrome://inspect
  • 3、点击devices标签,此时你会看到你设备上对应的App的包名
  • 4、点击包名旁边的inspect,就会进入chrome的调试工具,在这个调试工具就可以获取当前webview的所有元素了。