Macaca [基于 Node.js 的自动化测试-Macaca] - Macaca 是如何封装 ADB 的

达峰的夏天 · 2016年05月26日 · 最后由 达峰的夏天 回复于 2016年06月27日 · 2783 次阅读

上一篇 - Android 设备如何自动解锁

上篇文章提到了如何解锁 Android 设备,文章结尾提到了 adb 相关的内容,所以花几分钟时间说下 Macaca 是如何封装 adb 的。

ADB 是什么?

adb - Android Debug Bridge, 是 Android 平台开发和测试需要用到的最基本工具,当你安装完 ANDROID SDK 时它就已经存在了。

更详细的介绍和命令用法请到 command-line/adb

如何调用

macaca-adb 就是 Macaca 对 adb 的 Node.js 封装。通过查看源码可以发现,它对push pull forward install ... 等一些常用方法都有包装。

startApp 这个 api 为例,细述一下:

调用的方法如下,上篇文章已经提及过,将需要的 activitypackage name 通过参数传进去:

如何封装

startApp 方法会接收到需要的参数,然后拼接成为最终要执行的命令行执行

ADB.prototype.startApp = function() {
  var args = Array.prototype.slice.call(arguments);
  var options = args.shift();
  var activity = options.activity;
  var pkg = options.package;
  var shell = `am start -S -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -f 0x10200000 -n ${pkg}/${activity}`;

  args.unshift(shell);

  var promise = new Promise((resolve, reject) => {
    this.getApiLevel((err, apiLevel) => {

      if (parseInt(apiLevel, 10) > 15) {
        args[0] = `${args[0]} -S`;
      }

      this.shell.apply(this, args).then(data => {
        resolve(data);
      }).catch(err => {
        reject(`exec ${cmd} error with: ${err}`);
      });
    });
  });

  if (args.length > 1) {
    var cb = args[1];

    return promise.then(data => {
      cb.call(this, null, data);
    }).catch(err => {
      cb.call(this, `exec ${cmd} error with: ${err}`);
    });
  } else {
    return promise;
  }
};

执行的方式也很简单,直接使用 Node.js 提供的子进程运行,并且拿到执行结果透传即可:

_.exec = function(cmd, opts) {
  return new Promise(function(resolve, reject) {
    childProcess.exec(cmd, _.merge({
      maxBuffer: 1024 * 512,
      wrapArgs: false
    }, opts || {}), function(err, stdout, stderr) {
      if (err) {
        return reject(err);
      }
      resolve(_.trim(stdout));
    });
  });
};

其他的方法也都是使用同样的方式封装的,封装的过程中需要注意必要错误一定要抛出,避免用户遇到问题无法排查,或者无法被外围捕捉,需要容错的地方也要给出一定的提示。

启动参数?

解答下大家对 -f 0x10200000 启动参数的疑问。

先看下为什么会出现这个参数,这里的含义是 launchFlags,通过查看 Android SDK 提供的源码 Intent.java:

/**
 * If set, this activity will become the start of a new task on this
 * history stack.  A task (from the activity that started it to the
 * next task activity) defines an atomic group of activities that the
 * user can move to.  Tasks can be moved to the foreground and background;
 * all of the activities inside of a particular task always remain in
 * the same order.  See
 * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
 * Stack</a> for more information about tasks.
 *
 * <p>This flag is generally used by activities that want
 * to present a "launcher" style behavior: they give the user a list of
 * separate things that can be done, which otherwise run completely
 * independently of the activity launching them.
 *
 * <p>When using this flag, if a task is already running for the activity
 * you are now starting, then a new activity will not be started; instead,
 * the current task will simply be brought to the front of the screen with
 * the state it was last in.  See {@link #FLAG_ACTIVITY_MULTIPLE_TASK} for a flag
 * to disable this behavior.
 *
 * <p>This flag can not be used when the caller is requesting a result from
 * the activity being launched.
 */
public static final int FLAG_ACTIVITY_NEW_TASK = 0x10000000;

/**
 * If set, and this activity is either being started in a new task or
 * bringing to the top an existing task, then it will be launched as
 * the front door of the task.  This will result in the application of
 * any affinities needed to have that task in the proper state (either
 * moving activities to or from it), or simply resetting that task to
 * its initial state if needed.
 */
public static final int FLAG_ACTIVITY_RESET_TASK_IF_NEEDED = 0x00200000;

ok,打开你的浏览器 console 试试吧,这里相当于两个枚举值的或操作。

0x10200000 == Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

注:本例使用 API-19,不代表所有 API 版本。

欢迎讨论,互相学习。

微博: http://weibo.com/xudafeng
Github: https://github.com/xudafeng

下一篇 - 如何查找界面元素终极篇

共收到 1 条回复 时间 点赞
达峰的夏天 [该话题已被删除] 中提及了此贴 06月27日 11:17
达峰的夏天 [该话题已被删除] 中提及了此贴 06月27日 11:17
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册