Guide

记录使用 Appium 过程中关于 Appium 的一些代码定制情况

1.开启 webview 调试

获取 Webview 的 context 需要开发 app 的工程师在代码中添加开启 webview 调试的代码:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    WebView.setWebContentsDebuggingEnabled(true);
}

1.关闭创建 session 时推送 appium bootstrap 和安装 unlock 和 setting

一般安装过一次,不需要再重新安装,重新安装比较浪费时间,且有些安装时会有弹窗

1). 1.4.0 版本注释如下代码:

Appium\node_modules\appium\lib\devices\android\android.js

async.series([
    this.initJavaVersion.bind(this),
    this.initAdb.bind(this),
    this.packageAndLaunchActivityFromManifest.bind(this),
    this.initUiautomator.bind(this),
    this.prepareDevice.bind(this),
    this.checkApiLevel.bind(this),
    this.pushStrings.bind(this),
    this.processFromManifest.bind(this),
    this.uninstallApp.bind(this),
    this.installAppForTest.bind(this),
    this.forwardPort.bind(this),
    //this.pushAppium.bind(this),
    this.initUnicode.bind(this),
    // DO NOT push settings app and unlock app
    //this.pushSettingsApp.bind(this),
    //this.pushUnlock.bind(this),
    function (cb) {this.uiautomator.start(cb);}.bind(this),
    this.wakeUp.bind(this),
    this.unlock.bind(this),
    this.getDataDir.bind(this),
    this.setupCompressedLayoutHierarchy.bind(this),
    this.startAppUnderTest.bind(this),
    this.initAutoWebview.bind(this),
    this.setActualCapabilities.bind(this)
  ], function (err) {

2) Appium Desktop 版本(appium server 1.6.5 版本)

C:\Users\XXX\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\appium-android-driver\build\lib\ android-helpers.js
注释 UnlockApp 的安装

注释 SettingApp 的安装

3. 取消重新安装 UnicodeIME 输入法

1). 1.4.0 版本修改如下代码:

Appium\node_modules\appium\lib\devices\android\android-common.js


androidCommon.pushUnicodeIME = function (cb) {
  cb()
  /*
  logger.debug("Pushing unicode ime to device...");
  var imePath = path.resolve(__dirname, "..", "..", "..", "build",
      "unicode_ime_apk", "UnicodeIME-debug.apk");
  fs.stat(imePath, function (err) {
    if (err) {
      cb(new Error("Could not find Unicode IME apk; please run " +
                   "'reset.sh --android' to build it."));
    } else {
      this.adb.install(imePath, false, cb);
    }
  }.bind(this));
  */
};

2) Appium Desktop 版本(appium server 1.6.5 版本)

C:\Users\XXX\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\appium-android-driver\build\lib\ android-helpers.js

4. 修改 Appium 屏幕截图超时时间

报错信息:

2017-03-23 09:45:45:074 - info: [debug] Responding to client with error: {"status":13,"value":{"message":"An unknown server-side error occurred while processing the command. (Original error: Timed out waiting for screenshot file. Error: ENOENT, open '/tmp/appium-instruments/Run 1/screenshotbf5aafb9-913d-4287-9f9c-6690272a73a6.png')","origValue":"Timed out waiting for screenshot file. Error: ENOENT, open '/tmp/appium-instruments/Run 1/screenshotbf5aafb9-913d-4287-9f9c-6690272a73a6.png'"},"sessionId":"40928b8b-2c88-4a98-929b-cb0d8738b4ef"}
2017-03-23 09:45:45:076 - info: <-- GET /wd/hub/session/40928b8b-2c88-4a98-929b-cb0d8738b4ef/screenshot 500 42145.797 ms – 470

解决办法:

  1. 修改 *ios-controller.js *文件 加长超时时间 (默认为 10 秒) 目录:/Applications/Appium.app/Contents/Resources/node_modules/appium/lib/devices/ios/ios-controller.js

5. Android7.0 修改为授权安装

adb install [-lrtsdg] <file> 
                   - push this package file to the device and install it 
                        (-l: forward lock application) 
                        (-r: replace existing application) 
                        (-t: allow test packages) 
                        (-s: install application on sdcard)
                        (-d: allow version code downgrade (debuggable packages only)) 
                        (-g: grant all runtime permissions)

修改文件:
C:\Users\stephen\AppData\Local\Programs\appium-desktop\resources\app\node_modules\appium\node_modules\appium-adb\build\lib\tools\apk-utils.js

注:摘自 https://testerhome.com/topics/9118#reply18, 未亲自实验

6. Andriod6.0 系统获取 webiew 名称为 WEBVIEW_undefined

问题:
获取到的 webview 名称为 WEBVIEW_undefined

日志:

I found what's the problem, On Android 6.0 sometimes get WEBVIEW_undefined for this reason:
When we are getting the webview name, appium executes:
�info:  [debug] Getting a list of available webviews
�info:  [debug] executing cmd: /Users/android-sdk-macosx/platform-tools/adb -s PB029827 shell "cat /proc/net/unix"
�info:  [debug] WEBVIEW_25203 mapped to pid 25203
�info:  [debug] Getting process name for webview
�info:  [debug] executing cmd: /Users/android-sdk-macosx/platform-tools/adb -s PB029827 shell "ps"
�info:  [debug] pkgColumn: 8
�info:  [debug] Parsed pid: 25203 pkg: com.bqreaders.reader.nubicoapp
�info:  [debug] from: u0_a612,25203,188,985288,36316,ffffffff,00000000,R,com.XXX.XXX.XXX
�info:  [debug] returning process name: com.bqreaders.reader.nubicoapp
�info:  [debug] Available contexts: 
��info:  [debug] ["WEBVIEW_com.XXX.XXX.XXX"]
�info:  [debug] Available contexts: NATIVE_APP,WEBVIEW_com.XXX.XXX.XXX

分析:
There are 9 fields in Android 5.0 at boot time, but in Android 6.0 prints 8 fields at boot time:
Android 5.0
USER PID PPID VSIZE RSS WCHAN PC NAME
u0_a611 23802 188 1169748 133272 ffffffff 00000000 S com.XXX.XXX.XXX

Android 6.0
USER PID PPID VSIZE RSS WCHAN PC NAME
u0_a178 6346 211 1724936 123260 00000000 R com.XXX.XXX.XXX

But a few seconds later there are 9 fields
USER PID PPID VSIZE RSS WCHAN PC NAME
u0_a182 10156 211 1721024 111224 sys_epoll_ 00000000 S com.XXX.XXX.XXX
sys_epoll_ field is not visible until a few seconds later
So, when we are trying to get the webview name over 8 fields instead of 9, we get an "undefined"

解决方法 1:
修改 appium 安装包下的 lib/devices/android/android-hybrid.js 文件,在 pkg=line[pkgColumn] 前加上 pkgColumn=line.length-1

解决方法 2:加判断
https://github.com/appium/appium/commit/ee14df498aa8d2bd852a2a552329c899a49af424

_.find(lines, function (line) {
  line = line.trim().split(/\s+/);
  if (line[pidColumn].indexOf(pid) !== -1) {
    if (typeof line[pkgColumn] != 'undefined') {
      logger.debug("Parsed pid: " + line[pidColumn] + " pkg: " + line[pkgColumn]);
      logger.debug("from: " + line);
      pkg = line[pkgColumn];
    } else {
      logger.debug("Parsed pid: " + line[pidColumn] + " pkg: " + line[pkgColumn-1]);
      logger.debug("from: " + line);
      pkg = line[pkgColumn-1];            
    }   
    return pkg; // exit from _.find
  }
});
 });

参考信息:
https://github.com/appium/appium/issues/5689
https://github.com/appium/appium/blob/88e67ce987d78ce44de252219e07dc176a3511c2/lib/devices/android/android-hybrid.js#L99-109

7. 切换 webiew 超时或失败,报错"chrome not reachable"

解决办法:
a. 更新 chromedriver
chromedriver 下载地址:https://chromedriver.storage.googleapis.com/index.html(连不上请 ***)

b. 更新手机里的 andriod.system.webview
webview 下载地址:https://www.apkmirror.com/apk/google-inc/android-system-webview/(连不上请 ***)

分析过程:
Many of our tests run automation in the webview context. We started encountering issues with switching to the webview context on Android 6.0 and more recently N preview. This flakiness ranged from minute long delays to chromedriver failures, depending on how successful appium was in retrying its attempt to start a chromedriver session.
Solution
This chromedriver issue seems to be the root cause for these errors. I believe Appium faced the same issue that resulted in webview_undefined context names.
I have locally built the change into chromedriver and so far have not seen the errors recur.

Necessary changes
The necessary code changes are in this gist.
Edit: found a pull request addressing this issue.
Feel free to build it in chromedriver and test it out until chromedriver merges and releases the fix. I'm not sure how open appium is to including a custom build of chromedriver in their package.
EDIT
The fix is available in ChromeDriver 2.23!

参考:https://bugs.chromium.org/p/chromedriver/issues/detail?id=1378#c4

8. 切换 webview 报错 Chrome version must be >= 51.0.2704.0

日志:

(Original error: unknown error: Chrome version must be >= 51.0.2704.0
(Driver info: chromedriver=2.23.409699 (49b0fa931cda1caad0ae15b7d1b68004acd05129),platform=Windows NT 10.0.10240 x86_64))
at JWProxy.command$ (lib/proxy.js:133:15)
at tryCatch (C:\Program Files (x86)\Appium\node_modules\appium\node_modules\appium-chromedriver\node_modules\appium-jsonwp-proxy\node_modules\babel-runtime\regenerator\runtime.js:67:40)

原因:
chromedriver 版本需要对应 webview 的版本
解决办法:

  1. 更新手机里 webview 即可,可网上下载 com.google.android.webview.apk 进行安装 webview 下载地址:https://www.apkmirror.com/apk/google-inc/android-system-webview/(连不上请 ***)
  2. 降低 chromedriver 版本 chromedriver 下载地址:https://chromedriver.storage.googleapis.com/index.html(连不上请 ***)

建议:webview 和 chromedriver 都升级成最版本,老版本都或多或少存在一定程度的 bug

9. Android7.0 driver.pagesouce 报错 “bad pid uiautomator”

问题:获取页面报错 bad pid uiautomator

原因:
this.shell("ps '" + name + "'", function (err, stdout) 对于执行的指令是 ps ‘UIautomator’,android 7 不支持这个指令格式,所以执行结果是 bad pid 'uiautomator',所以需要修改指令执行方式 this.shell('ps ',name, function (err, stdout)

解决方案:
 修改 appium 中 adb.js 文件,在代码 var outlines = stdout.split(“\n”);后加 outlines.shift();
 目录:C:\Program Files\Appium\node_modules\appium\node_modules\appium-adb\lib

10. 手势滑动后 relese 报错 TouchUp fails after negative TouchMove

日志信息:

{"actions":[
{"action":"press","options":{"x":250,"y":945}},{"action":"wait","options":{"ms":1000}},  x: 250, y: 945
{"action":"moveTo","options":{"x":290,"y":0}},{"action":"wait","options":{"ms":1000}},   x: 540, y: 945
{"action":"moveTo","options":{"x":-290,"y":285}},{"action":"wait","options":{"ms":1000}},x: 250, y: 1230
{"action":"moveTo","options":{"x":290,"y":0}},{"action":"wait","options":{"ms":1000}},   x: 540, y: 1230
{"action":"moveTo","options":{"x":0,"y":290}},{"action":"wait","options":{"ms":1000}},   x: 540, y: 1520
{"action":"moveTo","options":{"x":280,"y":0}},{"action":"release"}]}                     x: 820,,y: 1520

> info: [debug] Pushing command to appium work queue: ["element:touchUp",{"x":-290,"y":285}]
> info: [debug] [BOOTSTRAP] [debug] Got data from client: {"cmd":"action","action":"element:touchUp","params":{"x":-290,"y":285}}
> info: [debug] [BOOTSTRAP] [debug] Got command of type ACTION
> info: [debug] [BOOTSTRAP] [debug] Got command action: touchUp
> info: [debug] [BOOTSTRAP] [debug] Display bounds: [0,0][1080,1920]
> info: [debug] [BOOTSTRAP] [debug] Returning result: {"status":29,"value":"Coordinate [x=-290.0, y=285.0] is outside of element rect: [0,0][1080,1920]"}
> info: [debug] Responding to client with error: {"status":29,"value":{"message":"The coordinates provided to an interactions operation are invalid.","origValue":"Coordinate [x=-290.0, y=285.0] is outside of element rect: [0,0][1080,1920]"},"sessionId":"fe416303-1c4c-43d8-98b7-37cbbb03b1b0"}
> info: <-- POST /wd/hub/session/fe416303-1c4c-43d8-98b7-37cbbb03b1b0/touch/perform 500 5244.519 ms – 243

分析:
根据日志信息和尝试,发现手势多次滑动时,如果存在往左滑动时,touchUp 的值会变成负值而报错,查看资料发现此 bug 在最新的版本中已修复,老版本 1.4.X 是未修复的,不太清楚怎么改,我们目前是通过 ‘设置手势密码只上、下、右滑动来避免此问题’

参考以下网址:
https://github.com/appium/appium/issues/6602
https://github.com/appium/appium-android-driver/pull/155/files
https://github.com/appium/appium/issues/7486
https://github.com/appium/java-client/issues/542


↙↙↙阅读原文可查看相关链接,并与作者交流