简书链接:Android基于AndroidStudio的测试研究自动点击实现解锁然后进入计算器输入我的QQ号码编写外挂如此简单
文章字数:1215,阅读全文大约需要4分钟
学完本篇文章,你会感觉你很想写自动点击方式的外挂了,就是这么爽,这么简单
,锁屏 点击 都那么easy.

1
2
3
4
5
6
7
8
9
10
11
12


dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3'//最新sdk18
}

简单的测试模板代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package cn.qssq666.androidtest;

import android.app.Instrumentation;
import android.os.RemoteException;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.util.Log;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
* Created by qssq on 2018/6/10 [email protected]
*/
@RunWith(AndroidJUnit4.class)
public class QssqTest {


private static final String TAG = "QssqTest";
Instrumentation mInstrumentation;
UiDevice mUiDevice;

@Before
public void before(){

mInstrumentation=InstrumentationRegistry.getInstrumentation();
mUiDevice=UiDevice.getInstance(mInstrumentation);

Log.w(TAG,"BEFORE RUN");
}
@Test
public void pressKey() throws RemoteException {

mUiDevice.pressRecentApps();

}


}

界面特征 破解语音红包也可以用这些思路,甚至根据标题大小,控件类型也可以.

介绍By类的用法

by类有如下经典的查找匹配方法
image.png

玩耍uiautomatorviewer

那么如何获取id呢,当然使用uiautomatorviewer啦!
获取id的方法

1
2
3
4
5
aaadeMBP:AndroidTest aaa$ cd $ANDROID_SDK_HOME/tools/bin
aaadeMBP:bin aaa$ ls
apkanalyzer avdmanager lint screenshot2 uiautomatorviewer
archquery jobb monkeyrunner sdkmanager

进入环境变量目录查看uiautomatorviewer文件,那么就启动它了.
image.png
image.png
系统通常是这样的android:id/text1 xml里面这是@android:id/text1 那么正常的是这样的
cn.qssq666.androidtest:id/tv_1而xml里面是这样的.@+id/tv_1
ok,讲解完毕开始上手按键的查找点击了. 因为按键查找实际上就是取的uiautomatorviewer里面id的字符串.

1
根据原理可以的出来,一个参数是包含了:id,分割开的话就只要资源名称和包名.不过为了方便通常是用这个工具获取所有全名称了.

*/
public BySelector res(String resourcePackage, String resourceId) {
checkNotNull(resourcePackage, “resourcePackage cannot be null”);
checkNotNull(resourceId, “resourceId cannot be null”);

    return res(Pattern.compile(Pattern.quote(
            String.format("%s:id/%s", resourcePackage, resourceId))));
}
1
2
3
4
5
6
7
8
9
10
11
12
quote的意思就是把里面可能存在的正则自动转义,亏我以前手写,原来有这么简单的方式.

### 高级功能
![image.png](https://upload-images.jianshu.io/upload_images/2815884-b09efd0e2b6045e7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![image.png](https://upload-images.jianshu.io/upload_images/2815884-137f7940bef25f8d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
### 实战代码


#### 进入编辑短信界面 确保2个输入框都同时存在
这里演示使用原生模拟器
![image.png](https://upload-images.jianshu.io/upload_images/2815884-71e8fc782129a53a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
下面的话的意思是获取获取了焦点的编辑框,然后输入一些内容而且这内容会把之前的内容
@Test
public void testSms() {

    BySelector focused = By.focused(true);
    UiObject2 object = mUiDevice.findObject(focused);
    if (object == null) {
        throw new RuntimeException("当前界面没有空间获取到了焦点");
    } else {

// object.click();//编辑框点击会弹出一个菜单,导致之后的逻辑无法正常执行抛出异常
String text = object.getText();
String className = object.getClassName();
Log.w(TAG, “当前text:” + text + “,” + className);
object.setText(“我插入了你,beflore:” + text + “,className:” + className);//StaleObjectException
}

}
1
2
3


#### 进入计算器界面输入数字

@Test
public void findView() {
//android:id/text1
/* BySelector bySelector = By.res(“cn.qssq666.androidtest:id/text1”);
System.out.println(“bySelector:”+bySelector);
// BySelector bySelector = By.res(“android:id/text1”);
mUiDevice.findObject(bySelector).setText(“我修改了android:text1”);

*/

    UiObject2 object = mUiDevice.findObject(By.res("com.android.calculator2:id/digit_7"));
    if (object != null) {
        object.setText("修改");//修改是无效的
        object.click();

        UiObject2 object1 = mUiDevice.findObject(By.text("0"));
        object1.click();

        mUiDevice.findObject(By.desc("加")).click();
        mUiDevice.findObject(By.text("3")).click();
        mUiDevice.findObject(By.text("5")).click();
        mUiDevice.findObject(By.text("0")).click();
        mUiDevice.findObject(By.text("6")).click();
        mUiDevice.findObject(By.text("8")).click();
        mUiDevice.findObject(By.text("2")).click();
        mUiDevice.findObject(By.text("6")).click();
        mUiDevice.findObject(By.text("4")).click();

    } else {
        Log.e(TAG, "没有打开计算器!");
    }


    BySelector bySelector1 = By.res(BuildConfig.APPLICATION_ID, "text1");
    UiObject2 object1 = mUiDevice.findObject(bySelector1);
    if (object1 != null) {
        object1.setText("我修改了当前包名text1");

    } else {
        Log.w(TAG, "没有找到是否运行了" + BuildConfig.APPLICATION_ID + "呢!");
    }
}
1
2
3
4
5
6
7

![image.png](https://upload-images.jianshu.io/upload_images/2815884-ca810a1966e4b217.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)



### 高级实战编写完整业务逻辑
我要做的就是在任意界面执行这段代码就可以实现锁屏然后解锁然后找到计算器应用然后滑动打开菜单输入根号然后关闭菜单输入我的数字得到我的QQ号码

@Test
public void fromLockScreenEnterCalc() throws RemoteException {
//滑动解锁,->点击计算器应用->滑动按下根号,然后按下 9
if (mUiDevice.isScreenOn()) {//没有锁屏那么就进行锁屏呗

// int x=528;//
mUiDevice.pressKeyCode(KeyEvent.KEYCODE_BACK);
mUiDevice.pressKeyCode(KeyEvent.KEYCODE_HOME);
mUiDevice.pressKeyCode(KeyEvent.KEYCODE_POWER);//回到home页,然后锁屏,
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}

    } else {
        mUiDevice.pressKeyCode(KeyEvent.KEYCODE_HOME);
    }

    //亮屏

    mUiDevice.pressKeyCode(KeyEvent.KEYCODE_POWER);
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    int step = 200 / 10;

    int x = 1080 / 2;//
    //解锁屏幕 从屏幕底部往上面0坐标滑动
    mUiDevice.swipe(x, 1080, x, 0, step);


    UiObject2 calc = mUiDevice.findObject(By.desc("计算器"));

    if (calc == null) {
        //锁屏了还需要做一个操作,就是点击一个图标向上的箭头
        UiObject2 current = mUiDevice.findObject(By.text("应用列表"));
        if (current == null) {
            current = mUiDevice.findObject(By.res("com.google.android.apps.nexuslauncher:id/all_apps_handle"));
            //com.google.android.apps.nexuslauncher:id/all_apps_handle
            if (current == null) {
                throw new RuntimeException("找不到计算器也找不到展开所有应用的图标按钮");
            }
        }


        current.click();
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {

            e.printStackTrace();
        }


        calc = mUiDevice.findObject(By.desc("计算器"));
        if (calc == null) {
            throw new RuntimeException("找不到计算器");
        }

    }


    calc.click();
    try {
        Thread.sleep(1500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    mUiDevice.swipe(1080 - 5, 1285, 8, 1285, 500 / 10);//steps 可能是1秒


    UiObject2 object = mUiDevice.findObject(By.res("com.android.calculator2:id/op_add"));
    if (object == null) {
        object = object.findObject(By.text("√)"));

    }
    if (object == null) {
        throw new RuntimeException("抱歉,找不到开根号按钮");
    }
    object.click();


    //按返回键关闭根号菜单
    mUiDevice.pressKeyCode(KeyEvent.KEYCODE_BACK);
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

// mUiDevice.pressKeyCode(KeyEvent.KEYCODE_9);

    pressMulti("9");
    pressMulti("=");
    pressMulti("+");
    pressMulti("3");
    pressMulti("5");
    pressMulti("0");
    pressMulti("6");
    pressMulti("8");
    pressMulti("2");
    pressMulti("6");
    pressMulti("1");
    pressMulti("=");

    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();

    }

     object = mUiDevice.findObject(By.res("com.android.calculator2:id/result"));
    if(object==null){
        object=mUiDevice.findObject(By.text("35068264"));
    }
    if(object==null){
        throw new RuntimeException("无法得知结果");
    }
    String str=object.getText();
    assertEquals(str,"35068264");

}

private void pressMulti(String s) {


    UiObject2 object = mUiDevice.findObject(By.text(s));
    if (object == null) {
        throw new RuntimeException("找不到按键" + s);
    } else {
        object.click();
    }
}
最后的结果就是我的qq