本项目由 DreamStudio Research 维护。
- Mumu模拟器Python API
该项目是基于MuMu提供的MuMuManager.exe实现的Python API,可以通过Python代码控制MuMu模拟器的大量操作。
该项目要求你已经安装了MuMu模拟器,且Mumu模拟器版本>=4.0.0以上。
- 修复了 ADB 点击/输入命令在 MuMu 上的 shell 调用兼容性问题。
- 修复了并发场景下
select状态互串问题,Mumu实例索引上下文已线程隔离。 auto.create_handle新增backend和fps参数,默认backend='auto'。backend='auto'会优先使用 MuMu 官方高性能截图 SDK(mumu_sdk),失败时自动回退到scrcpy。
将本项目安装到您的Python环境中
pip install mumu-python-api-wlkjyy如需 GUI 自动化相关依赖(OpenCV + scrcpy):
pip install "mumu-python-api-wlkjyy[auto]"导入模块
from mumu.mumu import Mumu如果你的Mumu模拟器不是使用默认路径安装,则需要在创建Mumu对象时传入MuMuManager的路径。
默认路径C:\Program Files\Netease\MuMu Player 12\shell\MuMuManager.exe
from mumu.mumu import Mumu
Mumu(r'your_path').select(1)在Mumu模拟器种,操作模拟器通过索引,索引可以在创建时指定,也可以创建时自动分配,如果你不知道你的模拟器索引是多少,可以打开“Mumu多开器”,找到你的模拟器,最前面那个数字就是你的模拟器索引。
如果指定的操作需要操作模拟器,可以通过select方法选择模拟器
from mumu.mumu import Mumu
mumu = Mumu().select(1)对于选择多个模拟器时可以这样,一下4种方式都是等价的,均可以选择1、2、3号模拟器
from mumu.mumu import Mumu
# 第一种
mumu = Mumu().select([1, 2, 3])
# 第二种
mumu = Mumu().select(1, 2, 3)
# 第三种
mumu = Mumu().select((1, 2, 3))
# 也可以混合使用
mumu = Mumu().select([1, 2], 3)如果希望选择所有模拟器,可以使用以下两种方法
from mumu.mumu import Mumu
# 第一种
mumu = Mumu().select() # 当select什么都不传时,默认选择所有模拟器
# 第二种:通过all方法选择所有模拟器
mumu = Mumu().all()我希望开启索引为1的模拟器的root权限,然后启动它。
from mumu.mumu import Mumu
# 选择索引为1的模拟器
mumu = Mumu().select(1)
# 开启Root权限
mumu.permission.root.enable()
# 启动模拟器
mumu.power.start()带*的类是本项目提供的超类,并不是MuMu模拟器的API原生提供。
多线程场景建议在每个线程里单独执行一次select(...)后再调用 API,避免跨线程共享未选择索引的对象。
本项目提供了多个操作类,可以通过这些类实现对模拟器的控制。
说明:具官方文档,目前仅支持网络桥接驱动。
说明:安装桥接驱动需要管理员权限
Mumu().driver.bridge.install()说明:卸载桥接驱动需要管理员权限
Mumu().driver.bridge.uninstall()说明:开启ROOT权限需要在模拟器关机状态下进行
Mumu().select('your_index').permission.root.enable()说明:关闭ROOT权限需要在模拟器关机状态下进行
Mumu().select('your_index').permission.root.disable()Mumu().select('your_index').power.start()启动完成后打开指定包名的应用
Mumu().select('your_index').power.start('com.tencent.mobileqq')Mumu().select('your_index').power.shutdown()
# or
Mumu().select('your_index').power.stop()Mumu().select('your_index').power.restart()
# or
Mumu().select('your_index').power.reboot()Mumu().select('your_index').window.show()隐藏窗口(hidden)
Mumu().select('your_index').window.hidden()该方法可以接受4个参数,分别是x坐标、y坐标、宽度、高度
Mumu().select('your_index').window.layout(0, 0, 800, 600)如果只希望调整窗口的大小
Mumu().select('your_index').window.layout(None, None, 1080, 1920)也可以只调整一个参数
Mumu().select('your_index').window.layout(300, None, None, None)
# or
Mumu().select('your_index').window.layout(None, None, 1080, None)该方法接受一个参数,即apk文件的路径,当apk路径无法访问时,会抛出FileNotFoundError异常
Mumu().select('your_index').app.install(r'C:\test.apk')该方法接受一个参数,即应用的包名
Mumu().select('your_index').app.uninstall('com.miHoYo.Yuanshen')该方法接受一个参数,即应用的包名
# 启动原神
Mumu().select('your_index').app.launch('com.miHoYo.Yuanshen')该方法接受一个参数,即应用的包名
# 关闭原神
Mumu().select('your_index').app.close('com.miHoYo.Yuanshen')该方法接受一个参数,即应用的包名
# 判断原神是否存在
if (Mumu().select('your_index').app.exists('com.miHoYo.Yuanshen')):
print('原神已安装')
else:
print('原神未安装')该方法接受一个参数,即应用的包名
# 判断原神是否不存在
if (Mumu().select('your_index').app.doesntExists('com.miHoYo.Yuanshen')):
print('原神未安装')
else:
print('原神已安装')# 获取已经安装的应用列表
Mumu().select(1).app.get_installed()返回一个列表,当没有安装任何应用时,返回一个空列表
[
{
'package': 'com.miHoYo.Yuanshen', # 包名
'app_name': '原神', # 应用名称
'version': '4.1.8' # 版本号
},
]该方法接受一个参数,即应用的包名,返回一个字符串,running表示应用正在运行,stopped表示应用未运行,not_installed表示应用未安装
# 获取原神的状态
Mumu().select('your_index').app.state('com.miHoYo.Yuanshen')该方法接受一个参数,即模拟器的名称,返回一个list包含所创建的模拟器索引
举例:创建一个模拟器
Mumu().core.create()举例:创建5个模拟器
Mumu().core.create(5)举例:创建一个索引为10的模拟器
Mumu().select(10).core.create()从索引3开始创建5个模拟器
Mumu().select(3).core.create(5)从索引 3,20 开始,分别创建10次模拟器,索引依次递增(即创建3-12,20-29索引的模拟器)
Mumu().select(3, 20).core.create(10)该方法接受一个参数,即为克隆的数量,但是调用该方法前需要先选择一个模拟器,返回一个list包含所创建的模拟器索引
举例:克隆索引为2的模拟器
Mumu().select(2).core.clone()举例:复制索引为 2,4,6 的模拟器
Mumu().select(2, 4, 6).core.clone()举例:复制索引为2的模拟器,复制10次
Mumu().select(2).core.clone(10)举例:复制所有模拟器
Mumu().all().core.clone()该方法不需要传入参数,但是调用该方法前需要先选择一个模拟器,返回bool值,表示是否删除成功
举例:删除索引为2的模拟器
if Mumu().select(2).core.delete():
print('删除成功')举例:删除索引为2,4,6的模拟器
Mumu().select(2, 4, 6).core.delete()举例:删除所有模拟器(危险操作)
Mumu().all().core.delete()该方法接受一个参数,即为新的模拟器名称,但是调用该方法前需要先选择一个模拟器,返回bool值,表示是否重命名成功。
举例:重命名索引为2的模拟器为“测试”
if Mumu().select(2).core.rename('测试'):
print('重命名成功')举例:重命名索引为2,4,6的模拟器为“测试”
Mumu().select(2, 4, 6).core.rename('测试')举例:重命名所有的模拟器为“测试”
Mumu().all().core.rename('测试')该方法接受三个参数,调用该方法前需要先选择一个模拟器,返回bool值,表示是否备份成功。
| 参数 | 说明 |
|---|---|
| dir | 备份的路径 |
| name | 备份的名称 |
| zip | 是否使用zip压缩 |
举例:备份索引为2的模拟器到C盘目录 backup 下,名称为 test.mumudata,以非压缩的格式
if Mumu().select(2).core.export(r'C:\backup', 'test'):
print('备份成功')举例:备份索引为2,4,6的模拟器到C盘目录 backup 下,文件名基于 test 自动加后缀,以非压缩的格式
Mumu().select(2, 4, 6).core.export(r'C:\backup', 'test')举例:备份所有的模拟器到C盘目录 backup 下,文件名基于 test 自动加后缀,以压缩的格式
Mumu().all().core.export(r'C:\backup', 'test', True)该方法接受一个参数,即为备份文件的路径,如果传入一个列表,则表示导入多个,调用该方法前需要先选择一个模拟器,返回bool值,表示是否导入成功。
举例:导入C盘下的 test.mumudata 并创建模拟器
if Mumu().select(2).core.import_(r'C:\test.mumudata'):
print('导入成功')举例:导入C盘下的 test.mumudata 并创建模拟器,导入10次
Mumu().select(2).core.import_(r'C:\test.mumudata', 10)举例:导入C盘下的 test.mumudata 和D盘下的 test2.mumudata 并创建模拟器,分别导入10次
Mumu().select(2).core.import_([r'C:\test.mumudata', r'D:\test2.mumudata'], 10)该方法接受一个参数,即为CPU使用率,调用该方法前需要先选择一个模拟器,返回bool值,表示是否设置成功。
举例:在索引为2的模拟器中限制CPU为50%
Mumu().select(2).core.limit_cpu(50)举例:在索引为2,4,6的模拟器中限制CPU为50%
Mumu().select(2, 4, 6).core.limit_cpu(50)举例:在所有模拟器中限制CPU为50%
Mumu().all().core.limit_cpu(50)该类提供了安卓事件操作,可以通过该类实现对模拟器的操作。
调用类的所有方法前需要先选择一个模拟器,返回bool值,表示是否操作成功。 方法未特殊说明时,均无需传入参数。
Mumu().select(1).androidEvent.rotate()Mumu().select(1).androidEvent.go_home()Mumu().select(1).androidEvent.go_back()Mumu().select(1).androidEvent.top_most()Mumu().select(1).androidEvent.fullscreen()Mumu().select(1).androidEvent.shake()Mumu().select(1).androidEvent.screenshot()Mumu().select(1).androidEvent.volume_up()Mumu().select(1).androidEvent.volume_down()Mumu().select(1).androidEvent.volume_mute()Mumu().select(1).androidEvent.go_task()该方法接受两个参数,分别是经度和纬度
举例:在索引为2的模拟器中修改虚拟定位为经度114.1,纬度-23
Mumu().select(2).androidEvent.location(114.1, -23)举例: 在索引为2,4,6的模拟器中修改虚拟定位为经度114.1,纬度-23
Mumu().select(2, 4, 6).androidEvent.location(114.1, -23)举例:在所有模拟器中修改虚拟定位为经度114.1,纬度-23
Mumu().all().androidEvent.location(114.1, -23)该方法接受三个参数,分别是x轴、y轴、z轴
举例:在索引为2的模拟器中修改重力感应X=40,Y=20,Z=30
Mumu().select(2).androidEvent.gyro(40, 20, 30)举例:在索引为2,4,6的模拟器中修改重力感应X=40,Y=20,Z=30
Mumu().select(2, 4, 6).androidEvent.gyro(40, 20, 30)举例:在所有模拟器中修改重力感应X=40,Y=20,Z=30
Mumu().all().androidEvent.gyro(40, 20, 30)该方法接受三个参数,分别是快捷方式名称、快捷方式图标路径、应用包名
举例:在桌面创建索引为2的模拟器的快捷方式 test,图标用 C 盘的 test.ico,自动启动原神
Mumu().select(2).shortcut.create('test', r'C:\test.ico', 'com.miHoYo.Yuanshen')举例:在桌面创建索引为2,4,6的模拟器的快捷方式 test,图标用 C 盘的 test.ico,自动启动原神
Mumu().select(2, 4, 6).shortcut.create('test', r'C:\test.ico', 'com.miHoYo.Yuanshen')举例:在所有模拟器中创建快捷方式 test,图标用 C 盘的 test.ico,自动启动原神
Mumu().all().shortcut.create('test', r'C:\test.ico', 'com.miHoYo.Yuanshen')该方法无需传入参数,调用该方法前需要先选择一个模拟器,返回bool值,表示是否删除成功。
举例:删除索引为2的模拟器的快捷方式
Mumu().select(2).shortcut.delete()举例:删除索引为2,4,6的模拟器的快捷方式
Mumu().select(2, 4, 6).shortcut.delete()举例:删除所有模拟器的快捷方式
Mumu().all().shortcut.delete()该类提供了模拟器机型操作。这玩意非常的鸡肋!!
该方法接受一个参数,即为新的MAC地址,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
Mumu().select(1).simulation.mac_address('00:11:22:33:44:55')举例:为索引为1的模拟器随机生成一个MAC地址,两种方式均可
from mumu.constant import MacAddress
# 第一种:传入一个MAC地址
Mumu().select(1).simulation.mac_address(MacAddress.random())
# 第二种:当不传入参数时,表示随机生成一个MAC地址
Mumu().select(1).simulation.mac_address() 安卓12不允许应用获取IMEI
该方法接受一个参数,即为新的IMEI,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
Mumu().select(1).simulation.imei('123456789012345')举例:为索引为1的模拟器随机生成一个IMEI,两种方式均可
from mumu.constant import IMEI
# 第一种:传入一个IMEI
Mumu().select(1).simulation.imei(IMEI.random())
# 第二种:当不传入参数时,表示随机生成一个IMEI
Mumu().select(1).simulation.imei() 安卓12不允许应用获取IMSI
该方法接受一个参数,即为新的IMSI,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
Mumu().select(1).simulation.imsi('460000000000000')举例:为索引为1的模拟器随机生成一个IMSI,两种方式均可
from mumu.constant import IMSI
# 第一种:传入一个IMSI
Mumu().select(1).simulation.imsi(IMSI.random())
# 第二种:当不传入参数时,表示随机生成一个IMSI
Mumu().select(1).simulation.imsi() 该方法接受一个参数,即为新的Android ID,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
Mumu().select(1).simulation.android_id('1234567890123456')举例:为索引为1的模拟器随机生成一个Android ID,两种方式均可
from mumu.constant import AndroidID
# 第一种:传入一个Android ID
Mumu().select(1).simulation.android_id(AndroidID.random())
# 第二种:当不传入参数时,表示随机生成一个Android ID
Mumu().select(1).simulation.android_id() 该方法接受一个参数,即为新的设备型号,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
Mumu().select(1).simulation.model('MI 10')该方法接受一个参数,即为新的主板型号,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
Mumu().select(1).simulation.brand('Xiaomi')该方法接受一个参数,即为新的硬件型号,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
Mumu().select(1).simulation.solution('qcom')安卓12不允许应用获取手机号码
该方法接受一个参数,即为新的手机号码,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
Mumu().select(1).simulation.phone_number('18888888888')举例:随机设置一个手机号码,两种方式均可
from mumu.constant import PhoneNumber
# 第一种:传入一个手机号码
Mumu().select(1).simulation.phone_number(PhoneNumber.random())
# 第二种:当不传入参数时,表示随机生成一个手机号码
Mumu().select(1).simulation.phone_number() 该方法提供4个参数,选填一个即可。
举例:设置索引为1的模拟器的GPU型号为GeForce RTX 3090
Mumu().select(1).simulation.gpu_model('GeForce RTX 3090')举例:设置索引为1的模拟器的GPU型号为高配
Mumu().select(1).simulation.gpu_model(top_model=True)举例:设置索引为1的模拟器的GPU型号为低配
Mumu().select(1).simulation.gpu_model(low_model=True)举例:设置索引为1的模拟器的GPU型号为中配
Memu().select(1).simulation.gpu_model(middle_model=True)该类提供了模拟器配置文件操作。
在配置类中,不选择任何模拟器即操作全局配置(默认值)
该方法提供一个参数all_writable,当传入True时,表示获取所有可写的配置项,当传入False时,表示获取所有配置项,返回一个字典,表示所有配置项的键值对。
举例:获取所有配置项
Mumu().select(1).setting.all()举例:获取所有可写的配置项
Mumu().select(1).setting.all(True)该方法接受一个或多个参数,表示要获取的配置项,当获取单个配置项时,返回一个字符串,当获取多个配置项时,返回一个字典,表示所有配置项的键值对。
举例:获取指定一个或多个配置(返回字符串)
value = Mumu().select(1).setting.get('window_size_fixed')举例:获取多个配置项(返回字典)
dict_val = Mumu().select(1).setting.get('window_size_fixed', 'window_save_rect')该方法接受一个或多个参数,表示要设置的配置项,返回一个bool值,表示是否设置成功。
当传入参数的值为None时,表示还原默认值。
如果遇到需要写的配置键包含.或者-时,将.替换为两个_,-替换为三个_。
举例:修改索引为2的模拟器的配置 window_size_fixed 的值为 true
Mumu().select(2).setting.set(window_size_fixed=True)举例:修改索引为2的模拟器的配置 window_size_fixed 的值为 false,配置 window_save_rect 的值为 true
Mumu().select(2).setting.set(window_size_fixed=False, window_save_rect=True)修改索引为2的模拟器的还原配置 window_size_fixed 的值(将使用默认值)
Mumu().select(2).setting.set(window_size_fixed=None)该方法接受一个参数,即为JSON文件的路径,返回一个bool值,表示是否设置成功。
举例:
一个 utf8 格式 test.json 文件在C盘下,文件内容如下:
{
"window_save_rect": "true",
"window_size_fixed": "false"
}修改索引为2的模拟器的配置,通过JSON文件方式修改。
Mumu().select(2).setting.set_by_json(r'C:\test.json')该方法接受两个参数,分别是配置项和值,返回一个bool值,表示是否相等。
举例:判断索引为2的模拟器的配置 window_size_fixed 是否等于 true
if Mumu().select(2).setting.equal('window_size_fixed', True):
print('相等')
else:
print('不相等')该方法接受两个参数,分别是配置项和值,返回一个bool值,表示是否不相等。
举例:判断索引为2的模拟器的配置 window_size_fixed 是否不等于 true
if Mumu().select(2).setting.not_equal('window_size_fixed', True):
print('不相等')
else:
print('相等')该方法接受三个参数,分别是配置项、值和新值,返回一个bool值,表示是否修改成功。
举例:判断索引为2的模拟器的配置 window_size_fixed 是否等于 true,如果相等则修改为 false
Mumu().select(2).setting.equal_then_set('window_size_fixed', True, False)该方法接受三个参数,分别是配置项、值和新值,返回一个bool值,表示是否修改成功。
当不传入新值时,将自动设置值
举例:判断索引为2的模拟器的配置 window_size_fixed 是否不等于 true,如果不相等则修改为 true
Mumu().select(2).setting.not_equal_then_set('window_size_fixed', True, True)
# or
Mumu().select(2).setting.not_equal_then_set('window_size_fixed', True)该类提供了模拟器屏幕操作。
该方法接受两个参数,分别是宽度和高度,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
举例:修改索引为2的模拟器的分辨率为 800x600
Mumu().select(2).screen.resolution(800, 600)该方法不需要传入参数,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
该方法调整的分辨率为 1080x1920 DPI 为 480
举例:设置索引为2的模拟器的分辨率为手机分辨率
Mumu().select(2).screen.resolution_mobile()该方法不需要传入参数,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
该方法调整的分辨率为 1920x1080 DPI 为 280
举例:设置索引为2的模拟器的分辨率为平板分辨率
Mumu().select(2).screen.resolution_tablet()该方法不需要传入参数,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
该方法调整的分辨率为 3200x1440 DPI 为 400
举例:设置索引为2的模拟器的分辨率为超宽屏分辨率
Mumu().select(2).screen.resolution_ultrawide()该方法接受一个参数,即为新的DPI,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
举例:修改索引为2的模拟器的DPI为 240
Mumu().select(2).screen.dpi(240)该方法接受一个参数,即为新的亮度,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
参数范围为0-100
举例:修改索引为2的模拟器的亮度为 50
Mumu().select(2).screen.brightness(50)该方法接受一个参数,即为新的最大帧率,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
参数范围为1-240
举例:修改索引为2的模拟器的最大帧率为 60
Mumu().select(2).screen.max_frame_rate(60)
# or
Mumu().select(2).screen.max_frame_rate() # 缺省值为60该方法接受两个参数,分别是enable和dynamic_low_frame_rate_limit,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
| 参数 | 类型 | 说明 |
|---|---|---|
| enable | bool | 是否启用动态调整帧率 |
| dynamic_low_frame_rate_limit | int | 模拟器不是操作主窗口时,降低至的帧率,默认:15 |
举例:启用索引为2的模拟器的动态调整帧率,降低至15帧
Mumu().select(2).screen.dynamic_adjust_frame_rate(True, 15)举例:禁用索引为2的模拟器的动态调整帧率
Mumu().select(2).screen.dynamic_adjust_frame_rate(False)该方法接受一个参数,即为enable,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
举例:启用索引为2的模拟器的垂直同步
Mumu().select(2).screen.vertical_sync(True)举例:禁用索引为2的模拟器的垂直同步
Mumu().select(2).screen.vertical_sync(False)该方法接受一个参数,即为enable,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
举例:启用索引为2的模拟器的显示帧率
Mumu().select(2).screen.show_frame_rate(True)举例:禁用索引为2的模拟器的显示帧率
Mumu().select(2).screen.show_frame_rate(False)该方法接受一个参数,即为enable,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
设置后,模拟器窗口会根据运行的应用自动旋转
举例:启用索引为2的模拟器的窗口自动旋转
Mumu().select(2).screen.window_auto_rotate(True)举例:禁用索引为2的模拟器的窗口自动旋转
Mumu().select(2).screen.window_auto_rotate(False)该类提供了模拟器性能操作。
该类的所有操作需要重启模拟器后生效。
该方法接受两个参数,分别是CPU个数和内存大小,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
CPU个数范围为1-16
内存大小范围为1-16,单位为GB,不支持小数
举例:设置索引为2的模拟器的CPU为4核,内存为4GB
Mumu().select(2).performance.set(4, 4)该方法接受一个参数,即为CPU个数,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
CPU个数范围为1-16
举例:设置索引为2的模拟器的CPU为4核
Mumu().select(2).performance.cpu(4)该方法接受一个参数,即为内存大小,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
内存大小范围为1-16,单位为GB,不支持小数
举例:设置索引为2的模拟器的内存为4GB
Mumu().select(2).performance.memory(4)该方法接受一个参数,即为enable,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
举例:启用索引为2的模拟器的强制使用独立显卡
Mumu().select(2).performance.force_discrete_graphics(True)举例:禁用索引为2的模拟器的强制使用独立显卡
Mumu().select(2).performance.force_discrete_graphics(False)该方法接受三个参数,选择一个即可。
举例:设置索引为2的模拟器的显存使用策略为自动
Mumu().select(2).performance.renderer_strategy(auto=True)
# or
Mumu().select(2).performance.renderer_strategy()举例:设置索引为2的模拟器的显存使用策略为资源占用更小
Mumu().select(2).performance.renderer_strategy(perf=True)举例:设置索引为2的模拟器的显存使用策略为画面表现更好
Mumu().select(2).performance.renderer_strategy(dis=True)该方法接受一个参数,即为enable,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
enable缺省值为True,开启时,磁盘类型为(只读系统盘,官方推荐),关闭时,磁盘类型为(可写系统盘)
本方法提供一个助手方法disk_writable,用于设置磁盘类型为可写系统盘。
举例:设置索引为2的模拟器的磁盘类型为只读系统盘。
Mumu().select(2).performance.disk_readonly(True)
# or
Mumu().select(2).performance.disk_readonly()举例:设置索引为2的模拟器的磁盘类型为可写系统盘
Mumu().select(2).performance.disk_readonly(False)
# or
Mumu().select(2).performance.disk_writable()该类提供了模拟器网络操作。
该方法返回一个列表,表示所有可被桥接的网卡。
举例:获取所有可被桥接的网卡
Mumu().select(1).network.get_bridge_card()示例返回:
['Realtek Gaming GbE Family Controller', 'Sangfor SSL VPN CS Support System VNIC', 'Microsoft KM-TEST 环回适配器',
'Intel(R) Wi-Fi 6E AX211 160MHz']该方法接受两个参数,分别代表是否启用和网卡名称,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
该方法需要安装“桥接驱动”才能使用。
举例:启用索引为2的模拟器的网络桥接模式,网卡名称为Realtek Gaming GbE Family Controller
Mumu().select(2).network.bridge(True, 'Realtek Gaming GbE Family Controller')举例:禁用索引为2的模拟器的网络桥接模式
Mumu().select(2).network.bridge(False)该方法无需传入参数,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
举例:设置索引为2的模拟器的网络为NAT模式
Mumu().select(2).network.nat()该方法无需传入参数,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
举例:设置索引为2的模拟器的桥接模式IP设置方式为DHCP
Mumu().select(2).network.bridge_dhcp()该方法接受5个参数,分别是IP地址、子网掩码、网关、DNS1、DNS2,调用该方法前需要先选择一个模拟器,返回bool值,表示是否修改成功。
当不填写DNS时,默认DNS1为8.8.8.8,DNS2为114.114.114.114
举例:设置索引为2的模拟器的桥接模式IP设置方式为静态,IP地址为192.168.10.10,子网掩码为255.255.255.0
,网关为192.168.10.1
Mumu().select(2).network.bridge_static('192.168.10.10', '255.255.255.0', '192.168.10.1')该类提供了ADB操作。
该无需传入参数,调用该方法前需要先选择一个模拟器,当选择一个模拟器时返回一个元组,包含IP和端口,当选择多个模拟器时返回一个字典,键为索引,值为IP和端口。
如果选择的模拟器无法获取到ADB连接信息,将返回None,None
举例:获取索引为2的模拟器的ADB连接信息
adb_ipaddr, adb_port = Mumu().select(2).adb.get_connect_info()举例:获取索引为2,4,6的模拟器的ADB连接信息
adb_info = Mumu().select(2, 4, 6).adb.get_connect_info()返回示例
{'2': ('172.30.20.123', 16416), '4': (None, None), '6': (None, None)}该方法接受两个参数,分别是X坐标和Y坐标,调用该方法前需要先选择一个模拟器,返回bool值,表示是否点击成功。
举例:点击索引为2的模拟器的坐标为(100, 100)的位置
Mumu().select(2).adb.click(100, 100)举例:点击索引为2,4,6的模拟器的坐标为(100, 100)的位置
Mumu().select(2, 4, 6).adb.click(100, 100)该方法提供5个参数,分别是起始X坐标、起始Y坐标、结束X坐标、结束Y坐标和滑动时间,调用该方法前需要先选择一个模拟器,返回bool值,表示是否滑动成功。
举例:滑动索引为2的模拟器的坐标为(100, 100)到(200, 200)的位置,时间为500ms
Mumu().select(2).adb.swipe(100, 100, 200, 200, 500)
# or
Mumu().select(2).adb.swipe(100, 100, 200, 200) # 缺省值为500ms举例:滑动索引为2,4,6的模拟器的坐标为(100, 100)到(200, 200)的位置,时间为500ms
Mumu().select(2, 4, 6).adb.swipe(100, 100, 200, 200, 500)该方法接受一个参数,即为要输入的文本,调用该方法前需要先选择一个模拟器,返回bool值,表示是否输入成功。
举例:在索引为2的模拟器中输入文本Hello World
Mumu().select(2).adb.input_text('Hello World')举例:在索引为2,4,6的模拟器中输入文本Hello World
Mumu().select(2, 4, 6).adb.input_text('Hello World')该方法接受一个参数,即为要模拟的按键,调用该方法前需要先选择一个模拟器,返回bool值,表示是否模拟成功。
举例:在索引为2的模拟器中模拟按键HOME
Mumu().select(2).adb.key_event(3)举例:通过本项目提供的按键常量模拟按键HOME
from mumu.constant import AndroidKey
Mumu().select(2).adb.key_event(AndroidKey.KEYCODE_HOME)举例:在索引为2,4,6的模拟器中模拟音量+
from mumu.constant import AndroidKey
Mumu().select(2, 4, 6).adb.key_event(AndroidKey.KEYCODE_VOLUME_UP)该方法接受两个参数,分别是本地文件路径和模拟器文件路径,调用该方法前需要先选择一个模拟器,返回bool值,表示是否上传成功。
当上传失败时,会触发一个warning警告。
举例:上传索引为2的模拟器的本地文件C:\test.txt到模拟器的/sdcard/test.txt
Mumu().select(2).adb.push(r'C:\test.txt', '/sdcard/test.txt')举例:上传索引为2,4,6的模拟器的本地文件C:\test.txt到模拟器的/sdcard/test.txt
Mumu().select(2, 4, 6).adb.push(r'C:\test.txt', '/sdcard/test.txt')该方法提供两个参数,分别是本地文件路径和模拟器文件名,调用该方法前需要先选择一个模拟器,返回bool值,表示是否上传成功。
当模拟器文件名为None时,将自动使用本地文件名。
举例:上传索引为2的模拟器的本地文件C:\test.txt到模拟器的Download目录
Mumu().select(2).adb.push_download(r'C:\test.txt')举例:上传索引为2,4,6的模拟器的本地文件C:\test.txt到模拟器的Download目录,重命名为:test1.txt
Mumu().select(2, 4, 6).adb.push_download(r'C:\test.txt', 'test1.txt')该方法提供两个参数,分别是模拟器文件路径和本地文件路径,调用该方法前需要先选择一个模拟器,返回bool值,表示是否下载成功。
当下载失败时,会触发一个warning警告。
举例:下载索引为2的模拟器的模拟器文件/sdcard/test.txt到本地的C:\test.txt
Mumu().select(2).adb.pull('/sdcard/test.txt', r'C:\test.txt')该方法接受一个参数,即为应用包名,调用该方法前需要先选择一个模拟器,返回bool值,表示是否清理成功。
如果包名错误会抛出异常
举例:清理索引为2的模拟器的应用数据
Mumu().select(2).adb.clear('com.miHoYo.Yuanshen')本类提供了模拟器的GUI自动化操作,例如:通过图片定位、坐标定位、文字定位实现自动化操作。
先决条件:需要安装opencv-python库,可以通过pip install opencv-python安装。
实时帧采集支持两种后端:
mumu_sdk(推荐):使用 MuMu 官方高性能截图接口,通常速度更高。scrcpy:兼容后端,需要安装scrcpy-client(pip install scrcpy-client)。
该方法接受三个参数:
handle:处理帧的回调方法。backend:auto/mumu_sdk/scrcpy,默认auto。fps:仅对mumu_sdk生效,表示采集帧率,默认30。
当backend='auto'时,优先使用mumu_sdk,如果不可用会自动回退到scrcpy。
handle方法包含两个参数frame和mumu,分别表示帧和当前模拟器对象。
frame为numpy数组,可以直接使用opencv的方法处理。
mumu为当前模拟器对象,仅选中了当前模拟器(线程隔离,可直接调用该对象的API)。
举例:处理索引为2的模拟器的帧
def handle(frame, mumu):
# do something
print('接收到模拟器:', mumu.core.utils.get_vm_id(), '的帧')
Mumu().select(2).auto.create_handle(handle)举例:处理索引为2,4,6的模拟器的帧
def handle(frame, mumu):
# do something
print('接收到模拟器:', mumu.core.utils.get_vm_id(), '的帧')
Mumu().select(2, 4, 6).auto.create_handle(handle)举例:强制使用MuMu SDK并设置帧率
Mumu().select(2).auto.create_handle(handle, backend='mumu_sdk', fps=60)举例:强制使用scrcpy后端
Mumu().select(2).auto.create_handle(handle, backend='scrcpy')该方法接受两个参数,分别为frame和path,用于保存模拟器的帧。
举例:保存帧到C:\test.png
def handle(frame, mumu):
mumu.auto.save(frame, r'C:\test.png')
Mumu().select(2).auto.create_handle(handle)举例:保存索引为3的模拟器的帧到C:\test.png
def handle(frame, mumu):
if mumu.core.utils.get_vm_id() == '3':
mumu.auto.save(frame, r'C:\test.png')
Mumu().select(2, 3).auto.create_handle(handle)该方法接受4个参数,分别为haystack、needle、confidence和grayscale,用于在帧中查找图片。
confidence为相似度,范围为0-1,缺省值为0.8
grayscale为是否使用灰度查找,缺省值为`False
举例:在帧中查找图片C:\test.png
def handle(frame, mumu):
# do something
print('接收到模拟器:', mumu.core.utils.get_vm_id(), '的帧')
pos = mumu.auto.locateOnScreen(frame, r'C:\test.png')
if pos:
print('找到图片:', pos)
else:
print('未找到图片')该方法接受4个参数,分别为haystack、needle、confidence和grayscale,用于在帧中查找图片。
confidence为相似度,范围为0-1,缺省值为0.8
grayscale为是否使用灰度查找,缺省值为`False
def handle(frame, mumu):
# do something
print('接收到模拟器:', mumu.core.utils.get_vm_id(), '的帧')
pos = mumu.auto.locateCenterOnScreen(frame, r'C:\test.png')
if pos:
print('找到图片中心点:', pos)
else:
print('未找到图片')该方法接受4个参数,分别为haystack、needle、confidence和grayscale,用于在帧中查找图片。
confidence为相似度,范围为0-1,缺省值为0.8
grayscale为是否使用灰度查找,缺省值为`False
def handle(frame, mumu):
# do something
print('接收到模拟器:', mumu.core.utils.get_vm_id(), '的帧')
pos = mumu.auto.locateAllOnScreen(frame, r'C:\test.png')
if pos:
print('找到图片:', pos)
else:
print('未找到图片')该方法接受一个参数,即为box,用于获取Box的中心点,返回x和y
box为一个元组,包含4个元素,分别为左上角x、左上角y、右下角x、右下角y
def handle(frame, mumu):
# do something
print('接收到模拟器:', mumu.core.utils.get_vm_id(), '的帧')
pos = mumu.auto.locateOnScreen(frame, r'C:\test.png')
if pos:
print('找到图片:', pos)
x, y = mumu.auto.center(pos)
print('中心点:', x, y)
else:
print('未找到图片')监听模拟器3的帧,当帧中出现test.png时,返回找到了,并返回当前时间和模拟器ID,然后返回到桌面。
def handle(frame, mumu: Mumu):
if mumu.auto.locateOnScreen(frame, './test.png', confidence=0.75, grayscale=True):
print("找到了", time.time(), '在模拟器', mumu.core.utils.get_vm_id())
mumu.androidEvent.go_home()
Mumu().select(3).auto.create_handle(handle)作者:wlkjyy
Mail:wlkjyy@vip.qq.com
WeCHAT:laravel_debug