Appium oppo 手机上运行 appium + python 遇到的坑

niky · 2017年07月24日 · 最后由 miqitangguo 回复于 2019年02月13日 · 4759 次阅读

目的

每次拉取共享路径上最新的被测 apk 包运行自动化用例,但是发现在 oppo r9s 手机上每次安装被测 app 、Settings 、unlock 程序的时候会弹出密码输入框,而且需要手动点击 “安装” 按钮。

解决问题 1:自动输入密码且点击安装

实现原理:使用 AccessibilityService 实现自动输入密码、点击安装按钮,步骤如下:
(1)新建 android 工程,创建 AutoInstallService ,如下

public class AutoInstallService extends AccessibilityService {
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        Log.d("InstallService", "onAccessibilityEvent");
        //针对oppo r9s,oppo手机上就是很麻烦需要点击多步安装
        sendInstallPassword("com.coloros.safecenter:id/et_login_passwd_edit","123456");//输入安装密码123456,不同的oppo时id还不一样
        clickInstallButton("android:id/button1");//点击安装按钮
        clickInstallButton("com.android.packageinstaller:id/btn_allow_once");//点击安装按钮
        clickInstallButton("com.android.packageinstaller:id/ok_button");//点击安装按钮
        clickInstallButton("com.android.packageinstaller:id/bottom_button_one");//点击完成按钮
    }

    private void sendInstallPassword(String id,String text){
        if(getRootInActiveWindow() == null)
            return;
        try{
            List<AccessibilityNodeInfo> nodes = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(id);
            if(nodes.size()==1){
                Log.d("AutoInstallService", "m的值:"+m);
                AccessibilityNodeInfo node = nodes.get(0);
                AccessibilityNodeInfo target = node.findFocus(AccessibilityNodeInfo.FOCUS_INPUT);
                if (target == null) {
                    Log.d("AutoInstallService", "inputPassword: null");
                    return;
                }
                ClipboardManager clipboard  = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
                ClipData clip = ClipData.newPlainText("label",text);
                clipboard.setPrimaryClip(clip);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                    target.performAction(AccessibilityNodeInfo.ACTION_PASTE);
                }
            }
        }catch (NullPointerException e){
            Log.d("AutoInstallService","没有找到控件");
        }
    }

    private void clickInstallButton(String id){
        if(getRootInActiveWindow() == null){
            return;
        }
        try{
            //以下操作针对oppo手机上,点击'继续安装'按钮
            List<AccessibilityNodeInfo> nodes = getRootInActiveWindow().findAccessibilityNodeInfosByViewId(id);
            for(int i = 0;i<nodes.size();i++){
                AccessibilityNodeInfo node = nodes.get(i);
                node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }
        }catch (NullPointerException e){
            Log.d("AutoInstallService","没有找到控件");
        }
    }

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        PrintUtils.log("onServiceConnected");
    }

    @Override
    public void onInterrupt() {
        PrintUtils.log("onInterrupt");
    }
}

(2)在 AndroidManifest.xml 中配置 service :

<service
    android:name=".service.AutoInstallService"
    android:enabled="true"
    android:exported="true"
    android:label="@string/app_name"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
    <intent-filter>
         <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <meta-data
           android:name="android.accessibilityservice"
           android:resource="@xml/auto_install_services_config" />
</service>

(3)安装该 apk 之后,在手机设置->辅助设置中打开该服务开关,安装 app 的时候回自动输入密码,自动点击安装:

解决问题 2:连接 appium 服务过程中提示中提示 " Activity used to start app doesn't exist or cannot be launched"

原因:使用 adb 命令行安装实际上是分两个步骤,第一步 push apk 包到 data 目录,第二步安装 apk ,oppo 手机比较特别的一点就是 push 到 data 目录开始安装的时候就会返回 success ,导致 apk 还没有安装完成 appium 就会 launch 入口 activity,导致提示 " Activity used to start app doesn't exist or cannot be launched" 。
解决方法:比较山寨,就是在连接 appium 服务之前提前安装被测 apk。

解决问题 3:当安装界面的 activity 存活的时候,再次调用 adb 命令安装的时候调不起安装界面,导致安装被测 apk 失败

每次安装之后调用 adb 命令退出安装 apk,adb.quit_app('com.android.packageinstaller'),如下:

for i in range(len(udids)):
    a = adb.ADB(udids[i])
    a.remove_app('com.lemon.faceu')
    apkPath = BASE_DIR + '/img/'+ runnerBase.getApkname()
    result = a.install_app(apkPath)
    while not result: #如果安装不成功,等待
        time.sleep(2)
    #oppo手机上的一个bug,需要杀死系统安装程序
    adb.ADB(udids[i]).quit_app('com.android.packageinstaller') #安装成功之后
main() #进入运行 case 流程
共收到 10 条回复 时间 点赞
niky 关闭了讨论 07月24日 11:53
niky 重新开启了讨论 07月24日 11:53

这个是不是也适用于小米手机

niky #4 · 2017年07月25日 Author
回复

适用哦,修改一下操作的控件即可

niky 回复

也是按你的这个教程来吧

niky #7 · 2017年07月25日 Author
AppetizerIO 回复

不介意哦,随意~~

niky #8 · 2017年07月25日 Author
回复

一样的,修改 AutoInstallService 里面控件的操作即可

大神,贴一下 auto_install_services_config 的配置啊。。。。

我这边弄了个自动安装的辅助工具,但是现在需要添加 “使用 AccessibilityService 实现自动输入密码”,如何实现了?

楼主 -- 有点懵,这个在 python 项目里是如何用的呢?

13楼 已删除

楼主,能上传一下完整的工程源码么

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册