通过ADB来实现脚本来控制手机
ADB
简介
adb的全称为Android Debug Bridge,安卓调试桥,可以通过调试命令来控制手机,诸如开机,关机等按键控制;或者启动,关闭应用;异或进行触摸模拟.
通过学习adb,可以实现简单的脚本控制,最大的特点是不需要root,对于普通手机都可以进行,帮助我们完成一些简单的重复性事件,诸如刷资源,各种app的签到
环境配置
电脑端
将下面3个文件弄到一个文件夹里D:\android\adb
,然后将其添加到path,adb环境就配置好了
AdbWinUsbApi.dll
AdbWinApi.dll
adb.exe
然后将这个文件夹添加到path中
cmd中 adb version
检查是否添加成功
手机端
开发者选项
开启开发者选项 : 以小米手机为例,先进入开发者设置,miui版本号点5下,更多设置->开发者选项->开启
打开usb调试 : 在开发者选项中,开启usb调试以便于执行adb指令,miui还需要开启usb调试(安全设置)
获取坐标 : 开发者选项中,开启指针位置以便于模拟触摸时获取位置
设备管理
远程调试
基于内网穿透实现远程调试,就可以不用占用那少得可怜的usb口了,下面是统一管理所有设备的命令
开启关闭服务,默认会自动开启,关闭服务可用于断开多个连接的设备
adb start-server
adb kill-server
adb devices 查看设备列表,如果有模拟器一般会自动连接,所以如果想在开模拟器时断开设备就需要获取模拟器ip:port然后断开
实现步骤
先使用内网穿透得到虚拟IP 如100.119.133.92
推荐tailscale或蒲公英
手机通过usb调试设置监听端口adb tcpip 5555
断开手机后,电脑连接 如adb connect 100.119.133.92:5555
调试结束后可以adb disconnect 100.119.133.92:5555
断开连接
远程控制
scrcpy 使用这个软件,在上面远程连接之后就可以进行远程控制,当然也可以直接连usb获得稳定的投屏
手机adb
- 先连接任意一个 Wi-Fi,就算没有接入互联网都可以;
- 然后打开 LADB,将它调整为小窗模式(或分屏模式)——因为无线调试的配对码等信息每次点击都会动态生成,所以才需要小窗模式同时打开本应用和开发者选项;
- 进入开发者选项,开启无线调试,首次使用需要配对设备,将配对码和端口填入本应用即可;
- 开心使用adb
应用管理
常见命令中常见pm和am的缩写
pm package manager
am activity manager
一个package下有多个activity(界面)
查看应用列表
adb shell pm list packages 查看所有应用
adb shell pm list packages -s 查看系统应用
adb shell pm list packages -3 查看第三方应用
adb shell pm list packages vivo 查看带关键词vivo的应用
安装应用
adb install [-r] [-d] [-g] <apk-file>
-r覆盖 -d降级覆盖 -g授予所有运行权限
例如 adb install "D:\android\apk\com.supercell.clashofclans.apk"
卸载应用
adb uninstall [-k] <package-name>
-k 表示卸载应用但保留数据和缓存目录。
例如adb uninstall com.supercell.clashofclans
获取activity和package
由adb shell dumpsys window w | findstr mCurrent
得到 mCurrentFocus=Window{8554b85 u0 com.supercell.clashofclans/com.supercell.titan.GameApp}
然后可以得到
activity : com.supercell.clashofclans/com.supercell.titan.GameApp
package : com.supercell.clashofclans
可以通过下面cmd代码获取
@echo off
setlocal enabledelayedexpansion
rem 先查询window w mCurrent属性,如果为空,则查询window w imeControlTarget属性
for /f "delims=" %%a in ('adb shell dumpsys window w ^| findstr mCurrent') do set activity=%%a
if "!activity!"=="" (
for /f "delims=" %%a in ('adb shell dumpsys window w ^| findstr imeControlTarget') do set activity=%%a )
rem 然后对获得的结果进行处理提取得到activity和package,先去除},然后取空格分隔的最后一部分,即activity,之后再得到package
for /f "delims=}" %%a in ("!activity!") do set activity=%%a
rem for /f "tokens=3 delims= " %%a in ("!activity!") do set activity=%%a
for %%I in (!activity!) do (set activity=%%I)
for /f "tokens=1 delims=/" %%a in ("!activity!") do set package=%%a
echo activity : !activity!
echo package : !package!
endlocal
提取安装包
获取了安装路径后pull到指定目录里并重命名为com.supercell.clashofclans.apk
adb shell pm path com.supercell.clashofclans
adb pull /data/app/com.supercell.clashofclans-HyrIPsbKlOHBjZwM4LnczA==/base.apk D:\android\com.supercell.clashofclans.apk
用cmd实现批量操作
@echo off
rem 获取安装包
set outputpath=D:\android\apk\
set package=com.supercell.clashofclans
for /f "delims=" %%a in ( 'adb shell pm path %package%' ) do set originalString=%%a
for /f "tokens=2 delims=:" %%a in ("%originalString%") do set apkpath=%%a
adb pull %apkpath% %outputpath%%package%.apk
启动和停止应用
rem 启动
adb shell am start -n com.supercell.clashofclans/com.supercell.titan.GameApp>nul
rem 强行停止
adb shell am force-stop com.supercell.clashofclans
行为模拟
按键模拟
按键模拟都是像下面这种格式,不同的按键对应不同的id
rem 模拟主页键
adb shell input keyevent 3
下面是常用id-按键表
id | 按键 |
---|---|
3 | home |
4 | 返回 |
187 | 多任务 |
24 | 增加音量 |
25 | 减小音量 |
26 | 电源键 |
164 | 静音 |
220 | 提高亮度 |
221 | 降低亮度 |
详细的见官网 KeyEvent | Android Developers
触摸模拟
rem 单击 (1200,70)为x,y坐标
adb shell input tap 1200 70
rem 滑动 从(600,700)滑动到(600,900)经历1000ms
adb shell input swipe 600 700 600 900 1000
rem 长按 用滑动实现
adb shell input swipe 100 100 100 100 1000
系统控制
rem 执行关机命令
adb shell reboot -p
rem 执行重启命令
adb shell reboot
rem 进入Recovery
adb reboot recovery
rem 进入Fastboot
adb reboot fastboot
实战
获取当前活动的activity和package
@echo off
setlocal enabledelayedexpansion
rem 先查询window w mCurrent属性
for /f "delims=" %%a in ('adb shell dumpsys window w ^| findstr mCurrent') do set activity=%%a
if "!activity!"=="" ( REM 如果没有查询到,则查询window w imeControlTarget属性,此处只试了两款手机,其他的可以自己打印出window w再找
for /f "delims=" %%a in ('adb shell dumpsys window w ^| findstr imeControlTarget') do set activity=%%a )
rem 然后对获得的结果进行处理提取得到activity和package,先去除},然后取空格分隔的最后一部分,即activity,之后再得到package
for /f "delims=}" %%a in ("!activity!") do set activity=%%a
rem 通过循环得到空格的最后一段,因为不同的指令输出的我们所需的信息都在最后
for %%I in (!activity!) do (set activity=%%I)
for /f "tokens=1 delims=/" %%a in ("!activity!") do set package=%%a
echo activity : !activity!
echo package : !package!
endlocal
coc辅助刷夜世界资源
坐标需要根据屏幕分辨率自行调整
chcp 65001
@echo off
set m=7
:m
set /a m+=1
adb shell am start -n com.supercell.clashofclans/com.supercell.titan.GameApp > nul
choice /t 12 /d y >nul
set /a n = %m% %% 8
if %n% == 0 (
echo 圣水已收集
adb shell input swipe 600 700 600 900 1000
adb shell input tap 1060 80
adb shell input tap 1100 600
adb shell input tap 1200 70
)
rem 皮卡一字滑
adb shell input tap 120 650
adb shell input tap 1035 500
choice /t 5 /d y >nul
adb shell input tap 360 650
FOR /L %%i in (1,1,2) DO (
adb shell input tap 200 100
adb shell input tap 200 450
adb shell input tap 1200 100
adb shell input tap 1200 450
)
adb shell am force-stop com.supercell.clashofclans
goto m
冲杯
chcp 65001
@echo off
if "%1" == "h" goto begin
mshta vbscript:createobject("wscript.shell").run("""%~nx0"" h",0)(window.close)&&exit
:begin
set m=7
:m
set /a m+=1
adb shell am start -n com.supercell.clashofclans/com.supercell.titan.GameApp > nul
choice /t 12 /d y >nul
set /a n = %m% %% 8
if %n% == 0 (
echo 圣水已收集
adb shell input swipe 600 700 600 900 1000
adb shell input tap 1000 200
adb shell input tap 1100 600
adb shell input tap 1200 70
)
adb shell input tap 120 650
adb shell input tap 1035 500
choice /t 5 /d y >nul
adb shell input tap 260 650
adb shell input tap 200 450
adb shell input tap 1200 100
adb shell input tap 360 650
FOR /L %%i in (1,1,2) DO (
adb shell input tap 200 100
adb shell input tap 200 450
adb shell input tap 1200 100
adb shell input tap 1200 450
)
choice /t 80 /d y >nul
adb shell input tap 260 650
adb shell input tap 200 450
adb shell input tap 1200 100
adb shell input tap 1100 660
FOR /L %%i in (1,1,3) DO (
adb shell input tap 200 100
adb shell input tap 200 450
adb shell input tap 1200 100
adb shell input tap 1200 450
)
adb shell am force-stop com.supercell.clashofclans
goto m
TODO
录制操作
record
#!/bin/bash -
if [ "$1" == "-h" ]; then
echo "-s: to generate Shell file "
echo "-c: to generate C program file "
echo "-h: help "
exit
fi
#apk信息
PACKAGE=$(awk -F '=' '$1~/PACKAGE/{print $2;exit}' ./config.ini)
ACTIVITY=$(awk -F '=' '$1~/LAUNCH_ACTIVITY/{print $2;exit}' ./config.ini)
#设备信息
DEVICE_NAME=$(awk -F '=' '$1~/DEVICE_NAME/{print $2;exit}' ./config.ini)
echo "Touch device is [ $DEVICE_NAME ]"
#文件定义
file=./out/cmds.txt
t0file=tmp0.txt
t1file=tmp1.txt
t2file=tmp2.txt
#-------------------------------------------------------------------------------
# 函数: 比较两个 Float 数值
#-------------------------------------------------------------------------------
compare_float(){
local a=$1
local b=$2
awk -va=$a -vb=$b 'BEGIN {if(a>b) printf("true"); else printf("false")}'
}
compare_string(){
local a=$1
local b=$2
awk -va=$a -vb=$b 'BEGIN {if(a!=b) printf("true"); else printf("false")}'
}
#组合事件过滤条件
echo "-----recorder started"
trap "echo '= recoder stopped ='" SIGINT
#重启app
adb shell am force-stop $PACKAGE
adb shell am start -W -n $PACKAGE/$ACTIVITY
#获取输出事件并重定向到文件
adb shell getevent -t | grep -E --line-buffered "$DEVICE_NAME" >$t0file
echo "-=============$DEVICE_NAME"
#替换"[","]","/dev/input/event/",":"为空字符串
sed 's/\[//g;s/\]//g;s/\/dev\/input\/event//g;s/\://g' $t0file >$t1file
#把文件中的相关内容格式化
#正则解释:
# 1. awk - 转换 第3列 和 第4列 数值为十进制模式(因为ioctl接收的是十进制)
# 2. sed - 4294967295 实为 -1, 原因是-1为0xFFFF,FFFF(4294967295)
cat $t1file |\
awk '{print $2, strtonum("0x"$3), strtonum("0x"$4), strtonum("0x"$5)}' |\
sed 's/4294967295/-1/g' >$t0file
#sleep_arry_line=() # 有睡眠操作的event
#sleep_arry_time=() # 保存睡眠时间
awk '{print $1}' $t1file >$t2file # 抽取时间列,存至 $t2file
tstart=$(sed -n '1p' $t2file)
tend=$(sed -n '$p' $t2file)
tdiff=0
index=1
while read t; do
case $t in
$tstart|$tend ) # 第一个时间和最后一个时间无需比较
tdiff=0.000000
;;
* )
prev=$(sed -n "$(($index-1)) p" $t2file)
tdiff=$(awk -va=$t -vb=$prev 'BEGIN {printf("%lf\n",a-b)}')
;;
esac
echo "$tdiff "
#sleep_arry_line+=($index)
sleep_arry_time+=($(awk -va=$tdiff 'BEGIN {print a*1000000}'))
((index++))
done < $t2file >$t1file
paste $t1file $t0file >$file
rm $t0file $t1file $t2file
echo "-----Generate txt file, output file is [ $file ]"
if ([[ $1 =~ "s" ]]); then
# 两个event时间差
# 因为一个触屏操作(如点击一下),需由多个event来组成
mindiff=0.01
shellfile="./out/cmds.sh"
scmdfile="scmd.txt"
ssleepfile="ssleep.txt"
ssleepfinalfile="sleep.txt"
awk '{print "sendevent /dev/input/event"$2" "$3" "$4" "$5}' $file >$scmdfile
awk '{print $1}' $file >$ssleepfile
index=1
while read t;do
if $(compare_float $mindiff $t); then
echo ''
else
echo "sleep $t; "
fi
done < $ssleepfile > $ssleepfinalfile
paste $ssleepfinalfile $scmdfile >$shellfile
rm $scmdfile $ssleepfinalfile $ssleepfile
adb push ./out/cmds.sh /data/local/tmp/cmds.sh
echo "-----Generate shell file , output file is [ $shellfile ]"
fi
if ([[ $1 =~ "c" ]]); then
modelcfile=template.c # 模板C语言文件
targetcfile=./jni/cmds.c
tcfile=tmpc.c
mindiff=$(awk -F '=' '$1~/TIME_INTERVAL/{print $2;exit}' ./config.ini)
currentdev=""
>$tcfile
while read line; do # 输出临时C语言文件
sleeptime=$(echo $line|awk '{print ($1)*1000000}')
device=$(echo $line|awk '{print "/dev/input/event"$2}')
type=$(echo $line|awk '{print $3}')
code=$(echo $line|awk '{print $4}')
value=$(echo $line|awk '{print $5}')
if $(compare_float $sleeptime $mindiff); then
echo " usleep($sleeptime);" >>$tcfile
fi
if $(compare_string $currentdev $device);then
currentdev=$device
cat<<EOF >>$tcfile
event.type = $type;
event.code = $code;
event.value = ${value}u;
fd = open("$device", O_RDWR);
write(fd, &event, event_size);
EOF
else
cat<<EOF >>$tcfile
event.type = $type;
event.code = $code;
event.value = ${value}u;
write(fd, &event, event_size);
EOF
fi
done < $file
append_line=55
sed "$append_line r $tcfile" $modelcfile >$targetcfile
rm $tcfile
echo "-----Generate C file , output file is [ $targetcfile ]"
#编译生成的c命令文件
cd ./jni
ndk-build
cd ../
cp ./libs/armeabi-v7a/cmds ./out/cmds
adb push ./out/cmds /data/local/tmp/cmds
rm -r ./libs ./obj
fi
#关闭app
adb shell am force-stop $PACKAGE
echo "-----Successfully, totally spent time: $SECONDS seconds"
replay
#apk信息
PACKAGE=$(awk -F '=' '$1~/PACKAGE/{print $2;exit}' ./config.ini)
ACTIVITY=$(awk -F '=' '$1~/LAUNCH_ACTIVITY/{print $2;exit}' ./config.ini)
#重启app
adb shell am force-stop $PACKAGE
adb shell am start -W -n $PACKAGE/$ACTIVITY
#回放事件
adb shell /data/local/tmp/cmds
#不同的手机权限系统不一样,如果你得手机需要root权限下才能运行回放命令,请替换为以下回放命令
#adb shell su -c busybox chmod 755 /data/local/tmp/cmds
#adb shell su -c /data/local/tmp/cmds
adb shell am force-stop $PACKAGE
ini
*******************************以下配置信息中不能有空格****************************************
#apk信息
PACKAGE="com.baidu.searchbox"
LAUNCH_ACTIVITY="com.baidu.searchbox.MainActivity"
#输入device信息,多个输入设备用“|”分隔
DEVICE_NAME=event2:|event9:
#两个事件之间的间隔,这个依据机器的性能而不同,需要手动设置,单位是微妙
TIME_INTERVAL=10000