通过ADB来实现脚本来控制手机

06-01 1659阅读

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来实现脚本来控制手机
(图片来源网络,侵删)

调试结束后可以adb disconnect 100.119.133.92:5555 断开连接

远程控制

scrcpy 使用这个软件,在上面远程连接之后就可以进行远程控制,当然也可以直接连usb获得稳定的投屏

通过ADB来实现脚本来控制手机
(图片来源网络,侵删)

手机adb

Local ADB

  • 先连接任意一个 Wi-Fi,就算没有接入互联网都可以;
  • 然后打开 LADB,将它调整为小窗模式(或分屏模式)——因为无线调试的配对码等信息每次点击都会动态生成,所以才需要小窗模式同时打开本应用和开发者选项;
  • 进入开发者选项,开启无线调试,首次使用需要配对设备,将配对码和端口填入本应用即可;
  • 开心使用adb

    安卓模拟器adb

    如使用mumu模拟器,可以在问题诊断里面查看adb端口

    通过ADB来实现脚本来控制手机
    (图片来源网络,侵删)

    找到端口后直接connect,如下是默认端口

    adb connect 127.0.0.1:16384
    

    应用管理

    常见命令中常见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] 
    -r覆盖 -d降级覆盖 -g授予所有运行权限
    

    例如 adb install "D:\android\apk\com.supercell.clashofclans.apk"

    卸载应用

    adb uninstall [-k] 
    -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
    

    行为模拟

    延时

    延时1s,以免过场动画影响操作,利用选择默认延迟来实现

    choice /t 1 /d y  >nul
    

    按键模拟

    按键模拟都是像下面这种格式,不同的按键对应不同的id

    rem 模拟主页键
    adb shell input keyevent 3
    

    下面是常用id-按键表

    id按键
    3home
    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
    

    使用python模拟adb

    下面是基于图像处理控制流程的coc辅助脚本

    里面的图片可以自己截取家乡界面和战斗界面的元素用于定位

    注意截图不能直接截,应该使用模拟器截图之后,再在截取的图片上面截

    因为模拟器的显示有缩放

    import cv2
    import numpy as np
    from PIL import Image
    import io
    import time
    import subprocess
    from adb_shell.adb_device import AdbDeviceTcp
    class AndroidDeviceController:
        def __init__(self, ip, port):
            self.device = AdbDeviceTcp(ip, port)
            self.device.connect(auth_timeout_s=0.1)
        def start_app(self, package_name, activity_name):
            self.device.shell(f"am start -n {package_name}/{activity_name}")
        def stop_app(self, package_name):
            self.device.shell(f"am force-stop {package_name}")
        def tap_screen(self, x, y):
            self.device.shell(f"input tap {x} {y}")
        def screen_shot(self):
            img_data = self.device.shell('screencap -p', decode=False)  # decode=False 保证是原始二进制数据
            image = Image.open(io.BytesIO(img_data))
            return np.array(image)
        def wait_scene(self, target_image_path, callback):
            target_image_path = "./img/"+target_image_path
            target_image = cv2.imread(target_image_path, cv2.IMREAD_GRAYSCALE)
            while True:
                screen = self.screen_shot()
                gray_screen = cv2.cvtColor(screen, cv2.COLOR_BGR2GRAY)
                result = cv2.matchTemplate(gray_screen, target_image, cv2.TM_CCOEFF_NORMED)
                min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
                threshold = 0.8   # 设置一个匹配的阈值
                if max_val >= threshold:
                    # match_loc = max_loc
                    # print(f"目标图像匹配位置: x={match_loc[0]}, y={match_loc[1]}")
                    callback()
                    break
                # else:
                #    print("未识别到目标")
                time.sleep(0.5)  # 每0.5秒进行一次截图进行匹配
    class GameController:
        def __init__(self, ip, port):
            self.controller = AndroidDeviceController(ip, port)
            self.round = 0
        def collect_elixir(self):
            if self.round % 5 == 0:
                self.round += 1
                self.controller.tap_screen(840, 10)
                time.sleep(0.5)
                self.controller.tap_screen(950, 600)
                self.controller.tap_screen(1070, 70)
                print("圣水已收集")
                time.sleep(1)
            else:
                self.round += 1
        def search_opponent(self):
            self.controller.tap_screen(120, 650)
            time.sleep(0.5)
            self.controller.tap_screen(1035, 500)
        def attack(self):
            self.controller.tap_screen(360, 650)
            for _ in range(2):
                self.controller.tap_screen(200, 100)
                self.controller.tap_screen(200, 450)
                self.controller.tap_screen(1200, 100)
                self.controller.tap_screen(1200, 450)
                time.sleep(1)
        def run(self):
            print("开始运行")
            while True:
                print(f'当前轮次:{self.round + 1}')
                self.controller.start_app('com.supercell.clashofclans', 'com.supercell.titan.GameApp')
                self.controller.wait_scene('setting.png', self.collect_elixir)
                self.search_opponent()
                self.controller.wait_scene('swap.png', self.attack)
                self.controller.stop_app('com.supercell.clashofclans')
    if __name__ == "__main__":
        game_controller = GameController('127.0.0.1', 16384)
        game_controller.run()
    
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码