This project is maintained by DreamStudio Research.
- MuMu Emulator Python API
- Project Overview
- How to Use
- API Classes
- Driver class (driver)
- Permission class (permission)
- Power class (power)
- Window class (window)
- App class (app)
- Install an app (install)
- Uninstall an app (uninstall)
- Launch an app inside the emulator (launch)
- Close an app inside the emulator (close)
- * Check whether an app exists (exists)
- * Check whether an app does not exist (doesntExists)
- Get the list of installed apps (get_installed)
- * Get app state (state)
- Core class (core)
- Android event class (androidEvent)
- Rotate screen (rotate)
- Go to home screen (go_home)
- Back (back)
- Pin window on top (top_most)
- Fullscreen window (fullscreen)
- Shake (shake)
- Screenshot (screenshot)
- Volume up (volume_up)
- Volume down (volume_down)
- Volume mute (volume_mute)
- Task key (go_task)
- Set virtual location (location)
- Set gyro sensor (gyro)
- Shortcut class (shortcut)
- Simulation class (simulation)
- Setting class (setting)
- Get all configuration items (all)
- Get one or more configuration items (get)
- Set one or more configuration items (set)
- Set configuration from a JSON file (set_by_json)
- * Check whether a config equals a value (equal)
- * Check whether a config does not equal a value (not_equal)
- * If a config equals a value, change it to another value (equal_then_set)
- * If a config does not equal a value, change it to another value (not_equal_then_set)
- * Screen class (screen)
- Set emulator resolution (resolution)
- Set to phone resolution (resolution_mobile)
- Set to tablet resolution (resolution_tablet)
- Set to ultrawide resolution (resolution_ultrawide)
- Set emulator DPI (dpi)
- Set emulator brightness (brightness)
- Set max frame rate (max_frame_rate)
- Set dynamic frame rate adjustment (dynamic_adjust_frame_rate)
- Set vertical sync (vertical_sync)
- Show frame rate (show_frame_rate)
- Auto-rotate window (window_auto_rotate)
- Performance class (performance)
- * Network class (network)
- ADB class (adb)
- GUI automation class (auto)
- Supporting This Project
This project is a Python API built on top of MuMu's MuMuManager.exe. It lets you control most operations of the MuMu emulator from Python.
The project requires that you already have MuMu Emulator installed, with version >=4.0.0.
- Fixed shell-invocation compatibility for ADB tap/input commands on MuMu.
- Fixed cross-talk of
selectstate under concurrency; the index context of aMumuinstance is now thread-isolated. auto.create_handlenow acceptsbackendandfpsparameters; default isbackend='auto'.backend='auto'prefers the official MuMu high-performance screenshot SDK (mumu_sdk) and automatically falls back toscrcpyif it is unavailable.
Install this project into your Python environment.
pip install mumu-python-api-wlkjyyIf you need the GUI automation extras (OpenCV + scrcpy):
pip install "mumu-python-api-wlkjyy[auto]"Import the module.
from mumu.mumu import MumuIf your MuMu emulator is not installed at the default path, you need to pass the path of MuMuManager when creating the Mumu object.
The default path is C:\Program Files\Netease\MuMu Player 12\shell\MuMuManager.exe.
from mumu.mumu import Mumu
Mumu(r'your_path').select(1)In the MuMu emulator, operations target an emulator by its index. The index can be specified at creation time or assigned automatically. If you don't know the index of your emulator, open the "MuMu Multi-Instance Manager", find your emulator, and the leading number is the index.
If an operation needs to act on an emulator, use the select method to choose one.
from mumu.mumu import Mumu
mumu = Mumu().select(1)To select multiple emulators, the following four forms are equivalent and all select emulators 1, 2, and 3.
from mumu.mumu import Mumu
# Form 1
mumu = Mumu().select([1, 2, 3])
# Form 2
mumu = Mumu().select(1, 2, 3)
# Form 3
mumu = Mumu().select((1, 2, 3))
# Forms can also be mixed
mumu = Mumu().select([1, 2], 3)To select all emulators, use either of the following.
from mumu.mumu import Mumu
# Form 1
mumu = Mumu().select() # Calling select with no arguments selects all emulators
# Form 2: select all emulators via the all method
mumu = Mumu().all()Suppose I want to enable root on emulator 1 and then launch it.
from mumu.mumu import Mumu
# Select emulator with index 1
mumu = Mumu().select(1)
# Enable root permission
mumu.permission.root.enable()
# Launch the emulator
mumu.power.start()Classes marked with * are super-classes provided by this project; they are not part of the native MuMu API.
In multi-threaded scenarios, it is recommended to call select(...) once per thread before invoking the API, to avoid sharing an unselected-index object across threads.
This project provides a number of operation classes that you can use to control the emulator.
Note: Per the official documentation, only the network bridge driver is currently supported.
Note: installing the bridge driver requires administrator privileges.
Mumu().driver.bridge.install()Note: uninstalling the bridge driver requires administrator privileges.
Mumu().driver.bridge.uninstall()Note: enabling ROOT must be done while the emulator is shut down.
Mumu().select('your_index').permission.root.enable()Note: disabling ROOT must be done while the emulator is shut down.
Mumu().select('your_index').permission.root.disable()Mumu().select('your_index').power.start()Launch the specified app once the emulator finishes starting.
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()Hide window (hidden)
Mumu().select('your_index').window.hidden()This method accepts 4 arguments: x coordinate, y coordinate, width, and height.
Mumu().select('your_index').window.layout(0, 0, 800, 600)To adjust only the window size:
Mumu().select('your_index').window.layout(None, None, 1080, 1920)You can also adjust a single argument.
Mumu().select('your_index').window.layout(300, None, None, None)
# or
Mumu().select('your_index').window.layout(None, None, 1080, None)This method accepts one argument, the path to an APK file. If the APK path is unreachable, FileNotFoundError is raised.
Mumu().select('your_index').app.install(r'C:\test.apk')This method accepts one argument: the app's package name.
Mumu().select('your_index').app.uninstall('com.miHoYo.Yuanshen')This method accepts one argument: the app's package name.
# Launch Genshin Impact
Mumu().select('your_index').app.launch('com.miHoYo.Yuanshen')This method accepts one argument: the app's package name.
# Close Genshin Impact
Mumu().select('your_index').app.close('com.miHoYo.Yuanshen')This method accepts one argument: the app's package name.
# Check whether Genshin Impact is installed
if (Mumu().select('your_index').app.exists('com.miHoYo.Yuanshen')):
print('Genshin Impact is installed')
else:
print('Genshin Impact is not installed')This method accepts one argument: the app's package name.
# Check whether Genshin Impact is not installed
if (Mumu().select('your_index').app.doesntExists('com.miHoYo.Yuanshen')):
print('Genshin Impact is not installed')
else:
print('Genshin Impact is installed')# Get the list of installed apps
Mumu().select(1).app.get_installed()Returns a list. When no apps are installed, returns an empty list.
[
{
'package': 'com.miHoYo.Yuanshen', # package name
'app_name': 'Genshin Impact', # app name
'version': '4.1.8' # version
},
]This method accepts one argument (the app's package name) and returns a string: running means the app is running, stopped means the app is not running, and not_installed means the app is not installed.
# Get Genshin Impact's state
Mumu().select('your_index').app.state('com.miHoYo.Yuanshen')This method accepts one argument (the number of emulators to create) and returns a list of the indices of the created emulators.
Example: create one emulator.
Mumu().core.create()Example: create 5 emulators.
Mumu().core.create(5)Example: create an emulator with index 10.
Mumu().select(10).core.create()Create 5 emulators starting from index 3.
Mumu().select(3).core.create(5)Starting from indices 3 and 20, create 10 emulators each, with indices increasing sequentially (i.e. emulators with indices 3-12 and 20-29).
Mumu().select(3, 20).core.create(10)This method accepts one argument (the number of clones). An emulator must be selected before calling this method. It returns a list of the indices of the created emulators.
Example: clone the emulator with index 2.
Mumu().select(2).core.clone()Example: clone the emulators with indices 2, 4, and 6.
Mumu().select(2, 4, 6).core.clone()Example: clone the emulator with index 2 ten times.
Mumu().select(2).core.clone(10)Example: clone all emulators.
Mumu().all().core.clone()This method takes no arguments. An emulator must be selected before calling it. It returns a bool indicating whether the deletion succeeded.
Example: delete the emulator with index 2.
if Mumu().select(2).core.delete():
print('Deleted successfully')Example: delete the emulators with indices 2, 4, and 6.
Mumu().select(2, 4, 6).core.delete()Example: delete all emulators (dangerous).
Mumu().all().core.delete()This method accepts one argument (the new emulator name). An emulator must be selected before calling it. It returns a bool indicating whether the rename succeeded.
Example: rename the emulator with index 2 to "test".
if Mumu().select(2).core.rename('test'):
print('Renamed successfully')Example: rename the emulators with indices 2, 4, and 6 to "test".
Mumu().select(2, 4, 6).core.rename('test')Example: rename all emulators to "test".
Mumu().all().core.rename('test')This method accepts three arguments. An emulator must be selected before calling it. It returns a bool indicating whether the backup succeeded.
| Parameter | Description |
|---|---|
| dir | Backup directory |
| name | Backup name |
| zip | Use zip compression |
Example: back up the emulator with index 2 to the C: drive's backup directory with the name test.mumudata, uncompressed.
if Mumu().select(2).core.export(r'C:\backup', 'test'):
print('Backup successful')Example: back up the emulators with indices 2, 4, and 6 to the C: drive's backup directory; the file names are derived from test with auto-appended suffixes, uncompressed.
Mumu().select(2, 4, 6).core.export(r'C:\backup', 'test')Example: back up all emulators to the C: drive's backup directory; the file names are derived from test with auto-appended suffixes, compressed.
Mumu().all().core.export(r'C:\backup', 'test', True)This method accepts one argument: the path to a backup file. If a list is passed, multiple files are imported. An emulator must be selected before calling it. It returns a bool indicating whether the import succeeded.
Example: import test.mumudata from the C: drive to create an emulator.
if Mumu().select(2).core.import_(r'C:\test.mumudata'):
print('Imported successfully')Example: import test.mumudata from the C: drive to create emulators, 10 times.
Mumu().select(2).core.import_(r'C:\test.mumudata', 10)Example: import test.mumudata from the C: drive and test2.mumudata from the D: drive to create emulators, 10 times each.
Mumu().select(2).core.import_([r'C:\test.mumudata', r'D:\test2.mumudata'], 10)This method accepts one argument: the CPU usage limit. An emulator must be selected before calling it. It returns a bool indicating whether the operation succeeded.
Example: limit the CPU of emulator 2 to 50%.
Mumu().select(2).core.limit_cpu(50)Example: limit the CPU of emulators 2, 4, and 6 to 50%.
Mumu().select(2, 4, 6).core.limit_cpu(50)Example: limit the CPU of all emulators to 50%.
Mumu().all().core.limit_cpu(50)This class exposes Android event operations, which you can use to drive the emulator.
An emulator must be selected before calling any method on this class. Each method returns a bool indicating success. Unless otherwise noted, methods take no arguments.
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()This method accepts two arguments: longitude and latitude.
Example: set the virtual location of emulator 2 to longitude 114.1, latitude -23.
Mumu().select(2).androidEvent.location(114.1, -23)Example: set the virtual location of emulators 2, 4, and 6 to longitude 114.1, latitude -23.
Mumu().select(2, 4, 6).androidEvent.location(114.1, -23)Example: set the virtual location of all emulators to longitude 114.1, latitude -23.
Mumu().all().androidEvent.location(114.1, -23)This method accepts three arguments: x, y, and z axes.
Example: set the gyro sensor of emulator 2 to X=40, Y=20, Z=30.
Mumu().select(2).androidEvent.gyro(40, 20, 30)Example: set the gyro sensor of emulators 2, 4, and 6 to X=40, Y=20, Z=30.
Mumu().select(2, 4, 6).androidEvent.gyro(40, 20, 30)Example: set the gyro sensor of all emulators to X=40, Y=20, Z=30.
Mumu().all().androidEvent.gyro(40, 20, 30)This method accepts three arguments: shortcut name, shortcut icon path, and app package name.
Example: create a desktop shortcut named test for emulator 2 using C:\test.ico as the icon, auto-launching Genshin Impact.
Mumu().select(2).shortcut.create('test', r'C:\test.ico', 'com.miHoYo.Yuanshen')Example: create a desktop shortcut named test for emulators 2, 4, and 6 using C:\test.ico as the icon, auto-launching Genshin Impact.
Mumu().select(2, 4, 6).shortcut.create('test', r'C:\test.ico', 'com.miHoYo.Yuanshen')Example: create a shortcut named test for all emulators using C:\test.ico as the icon, auto-launching Genshin Impact.
Mumu().all().shortcut.create('test', r'C:\test.ico', 'com.miHoYo.Yuanshen')This method takes no arguments. An emulator must be selected before calling it. It returns a bool indicating whether the deletion succeeded.
Example: delete the shortcut for emulator 2.
Mumu().select(2).shortcut.delete()Example: delete the shortcuts for emulators 2, 4, and 6.
Mumu().select(2, 4, 6).shortcut.delete()Example: delete the shortcuts for all emulators.
Mumu().all().shortcut.delete()This class exposes simulated-device operations. (These are largely cosmetic.)
This method accepts one argument (the new MAC address). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Mumu().select(1).simulation.mac_address('00:11:22:33:44:55')Example: generate a random MAC address for emulator 1; either form works.
from mumu.constant import MacAddress
# Form 1: pass a MAC address
Mumu().select(1).simulation.mac_address(MacAddress.random())
# Form 2: with no argument, a random MAC address is generated
Mumu().select(1).simulation.mac_address() Android 12 does not allow apps to read the IMEI.
This method accepts one argument (the new IMEI). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Mumu().select(1).simulation.imei('123456789012345')Example: generate a random IMEI for emulator 1; either form works.
from mumu.constant import IMEI
# Form 1: pass an IMEI
Mumu().select(1).simulation.imei(IMEI.random())
# Form 2: with no argument, a random IMEI is generated
Mumu().select(1).simulation.imei() Android 12 does not allow apps to read the IMSI.
This method accepts one argument (the new IMSI). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Mumu().select(1).simulation.imsi('460000000000000')Example: generate a random IMSI for emulator 1; either form works.
from mumu.constant import IMSI
# Form 1: pass an IMSI
Mumu().select(1).simulation.imsi(IMSI.random())
# Form 2: with no argument, a random IMSI is generated
Mumu().select(1).simulation.imsi() This method accepts one argument (the new Android ID). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Mumu().select(1).simulation.android_id('1234567890123456')Example: generate a random Android ID for emulator 1; either form works.
from mumu.constant import AndroidID
# Form 1: pass an Android ID
Mumu().select(1).simulation.android_id(AndroidID.random())
# Form 2: with no argument, a random Android ID is generated
Mumu().select(1).simulation.android_id() This method accepts one argument (the new device model). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Mumu().select(1).simulation.model('MI 10')This method accepts one argument (the new motherboard brand). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Mumu().select(1).simulation.brand('Xiaomi')This method accepts one argument (the new hardware manufacturer). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Mumu().select(1).simulation.solution('qcom')Android 12 does not allow apps to read the phone number.
This method accepts one argument (the new phone number). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Mumu().select(1).simulation.phone_number('18888888888')Example: set a random phone number; either form works.
from mumu.constant import PhoneNumber
# Form 1: pass a phone number
Mumu().select(1).simulation.phone_number(PhoneNumber.random())
# Form 2: with no argument, a random phone number is generated
Mumu().select(1).simulation.phone_number() This method exposes 4 parameters; pass one of them.
Example: set the GPU model of emulator 1 to GeForce RTX 3090.
Mumu().select(1).simulation.gpu_model('GeForce RTX 3090')Example: set the GPU model of emulator 1 to the high-end preset.
Mumu().select(1).simulation.gpu_model(top_model=True)Example: set the GPU model of emulator 1 to the low-end preset.
Mumu().select(1).simulation.gpu_model(low_model=True)Example: set the GPU model of emulator 1 to the mid-range preset.
Memu().select(1).simulation.gpu_model(middle_model=True)This class exposes operations on the emulator's configuration file.
In the setting class, when no emulator is selected, the operations target the global configuration (i.e. the defaults).
This method has one parameter all_writable. When True, it returns all writable configuration items; when False, it returns all configuration items. It returns a dict of key/value pairs.
Example: get all configuration items.
Mumu().select(1).setting.all()Example: get all writable configuration items.
Mumu().select(1).setting.all(True)This method accepts one or more arguments specifying the configuration items to retrieve. When fetching a single item, it returns a string; when fetching multiple items, it returns a dict of key/value pairs.
Example: get one configuration item (returns a string).
value = Mumu().select(1).setting.get('window_size_fixed')Example: get multiple configuration items (returns a dict).
dict_val = Mumu().select(1).setting.get('window_size_fixed', 'window_save_rect')This method accepts one or more arguments specifying the configuration items to set. It returns a bool indicating whether the change succeeded.
When the value is None, the default value is restored.
If a configuration key contains . or -, replace . with two _ and - with three _.
Example: set the window_size_fixed configuration of emulator 2 to true.
Mumu().select(2).setting.set(window_size_fixed=True)Example: set the window_size_fixed configuration of emulator 2 to false and window_save_rect to true.
Mumu().select(2).setting.set(window_size_fixed=False, window_save_rect=True)Restore the window_size_fixed configuration of emulator 2 (uses the default value).
Mumu().select(2).setting.set(window_size_fixed=None)This method accepts one argument: the path to a JSON file. It returns a bool indicating whether the change succeeded.
Example:
A UTF-8 encoded test.json file on the C: drive with the following contents:
{
"window_save_rect": "true",
"window_size_fixed": "false"
}Apply this configuration to emulator 2 via the JSON file.
Mumu().select(2).setting.set_by_json(r'C:\test.json')This method accepts two arguments: the configuration item and the value. It returns a bool indicating equality.
Example: check whether the window_size_fixed configuration of emulator 2 equals true.
if Mumu().select(2).setting.equal('window_size_fixed', True):
print('Equal')
else:
print('Not equal')This method accepts two arguments: the configuration item and the value. It returns a bool indicating inequality.
Example: check whether the window_size_fixed configuration of emulator 2 does not equal true.
if Mumu().select(2).setting.not_equal('window_size_fixed', True):
print('Not equal')
else:
print('Equal')This method accepts three arguments: the configuration item, the value, and the new value. It returns a bool indicating whether the change succeeded.
Example: check whether the window_size_fixed configuration of emulator 2 equals true; if so, change it to false.
Mumu().select(2).setting.equal_then_set('window_size_fixed', True, False)This method accepts three arguments: the configuration item, the value, and the new value. It returns a bool indicating whether the change succeeded.
When no new value is passed, the value argument is set automatically.
Example: check whether the window_size_fixed configuration of emulator 2 does not equal true; if not, change it to 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)This class exposes screen operations for the emulator.
This method accepts two arguments: width and height. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Example: set the resolution of emulator 2 to 800x600.
Mumu().select(2).screen.resolution(800, 600)This method takes no arguments. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
This method sets the resolution to 1080x1920 with DPI 480.
Example: set emulator 2 to phone resolution.
Mumu().select(2).screen.resolution_mobile()This method takes no arguments. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
This method sets the resolution to 1920x1080 with DPI 280.
Example: set emulator 2 to tablet resolution.
Mumu().select(2).screen.resolution_tablet()This method takes no arguments. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
This method sets the resolution to 3200x1440 with DPI 400.
Example: set emulator 2 to ultrawide resolution.
Mumu().select(2).screen.resolution_ultrawide()This method accepts one argument (the new DPI). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Example: set the DPI of emulator 2 to 240.
Mumu().select(2).screen.dpi(240)This method accepts one argument (the new brightness). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
The valid range is 0-100.
Example: set the brightness of emulator 2 to 50.
Mumu().select(2).screen.brightness(50)This method accepts one argument (the new max frame rate). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
The valid range is 1-240.
Example: set the max frame rate of emulator 2 to 60.
Mumu().select(2).screen.max_frame_rate(60)
# or
Mumu().select(2).screen.max_frame_rate() # default is 60This method accepts two arguments: enable and dynamic_low_frame_rate_limit. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
| Parameter | Type | Description |
|---|---|---|
| enable | bool | Whether to enable dynamic frame rate adjustment |
| dynamic_low_frame_rate_limit | int | Frame rate to drop to when the emulator window is not in focus, default: 15 |
Example: enable dynamic frame rate adjustment for emulator 2, dropping to 15 fps.
Mumu().select(2).screen.dynamic_adjust_frame_rate(True, 15)Example: disable dynamic frame rate adjustment for emulator 2.
Mumu().select(2).screen.dynamic_adjust_frame_rate(False)This method accepts one argument: enable. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Example: enable vertical sync for emulator 2.
Mumu().select(2).screen.vertical_sync(True)Example: disable vertical sync for emulator 2.
Mumu().select(2).screen.vertical_sync(False)This method accepts one argument: enable. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Example: enable frame-rate display for emulator 2.
Mumu().select(2).screen.show_frame_rate(True)Example: disable frame-rate display for emulator 2.
Mumu().select(2).screen.show_frame_rate(False)This method accepts one argument: enable. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
When enabled, the emulator window will rotate automatically based on the running app.
Example: enable window auto-rotate for emulator 2.
Mumu().select(2).screen.window_auto_rotate(True)Example: disable window auto-rotate for emulator 2.
Mumu().select(2).screen.window_auto_rotate(False)This class exposes performance operations for the emulator.
All operations in this class take effect after the emulator is restarted.
This method accepts two arguments: CPU count and memory size. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
The CPU count range is 1-16.
The memory size range is 1-16 (in GB, integers only).
Example: set emulator 2 to 4 CPU cores and 4 GB of memory.
Mumu().select(2).performance.set(4, 4)This method accepts one argument (the CPU count). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
The CPU count range is 1-16.
Example: set emulator 2 to 4 CPU cores.
Mumu().select(2).performance.cpu(4)This method accepts one argument (the memory size). An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
The memory size range is 1-16 (in GB, integers only).
Example: set emulator 2 to 4 GB of memory.
Mumu().select(2).performance.memory(4)This method accepts one argument: enable. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Example: enable forced discrete graphics for emulator 2.
Mumu().select(2).performance.force_discrete_graphics(True)Example: disable forced discrete graphics for emulator 2.
Mumu().select(2).performance.force_discrete_graphics(False)This method accepts three parameters; pass one of them.
Example: set the VRAM usage strategy of emulator 2 to auto.
Mumu().select(2).performance.renderer_strategy(auto=True)
# or
Mumu().select(2).performance.renderer_strategy()Example: set the VRAM usage strategy of emulator 2 to "lower resource usage".
Mumu().select(2).performance.renderer_strategy(perf=True)Example: set the VRAM usage strategy of emulator 2 to "better visual quality".
Mumu().select(2).performance.renderer_strategy(dis=True)This method accepts one argument: enable. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
The default for enable is True. When enabled, the disk type is "read-only system disk" (officially recommended); when disabled, the disk type is "writable system disk".
This method also exposes a helper disk_writable for setting the disk type to writable.
Example: set the disk type of emulator 2 to read-only system disk.
Mumu().select(2).performance.disk_readonly(True)
# or
Mumu().select(2).performance.disk_readonly()Example: set the disk type of emulator 2 to writable system disk.
Mumu().select(2).performance.disk_readonly(False)
# or
Mumu().select(2).performance.disk_writable()This class exposes network operations for the emulator.
This method returns a list of all bridgeable network cards.
Example: get all bridgeable network cards.
Mumu().select(1).network.get_bridge_card()Example return:
['Realtek Gaming GbE Family Controller', 'Sangfor SSL VPN CS Support System VNIC', 'Microsoft KM-TEST Loopback Adapter',
'Intel(R) Wi-Fi 6E AX211 160MHz']This method accepts two arguments: whether to enable bridging and the network card name. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
This method requires the "bridge driver" to be installed.
Example: enable bridge mode for emulator 2 with the card Realtek Gaming GbE Family Controller.
Mumu().select(2).network.bridge(True, 'Realtek Gaming GbE Family Controller')Example: disable bridge mode for emulator 2.
Mumu().select(2).network.bridge(False)This method takes no arguments. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Example: set the network of emulator 2 to NAT mode.
Mumu().select(2).network.nat()This method takes no arguments. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
Example: set the bridge IP mode of emulator 2 to DHCP.
Mumu().select(2).network.bridge_dhcp()This method accepts 5 arguments: IP address, subnet mask, gateway, DNS1, and DNS2. An emulator must be selected before calling it. It returns a bool indicating whether the change succeeded.
When the DNS arguments are omitted, the defaults are DNS1 = 8.8.8.8 and DNS2 = 114.114.114.114.
Example: set the bridge IP mode of emulator 2 to static, with IP 192.168.10.10, subnet mask 255.255.255.0,
and gateway 192.168.10.1.
Mumu().select(2).network.bridge_static('192.168.10.10', '255.255.255.0', '192.168.10.1')This class exposes ADB operations.
This method takes no arguments. An emulator must be selected before calling it. When a single emulator is selected, it returns a tuple of (IP, port); when multiple emulators are selected, it returns a dict whose keys are indices and whose values are (IP, port) tuples.
If the ADB connection info cannot be retrieved for a selected emulator, (None, None) is returned.
Example: get the ADB connection info of emulator 2.
adb_ipaddr, adb_port = Mumu().select(2).adb.get_connect_info()Example: get the ADB connection info of emulators 2, 4, and 6.
adb_info = Mumu().select(2, 4, 6).adb.get_connect_info()Example return:
{'2': ('172.30.20.123', 16416), '4': (None, None), '6': (None, None)}This method accepts two arguments: X and Y coordinates. An emulator must be selected before calling it. It returns a bool indicating whether the tap succeeded.
Example: tap (100, 100) on emulator 2.
Mumu().select(2).adb.click(100, 100)Example: tap (100, 100) on emulators 2, 4, and 6.
Mumu().select(2, 4, 6).adb.click(100, 100)This method accepts 5 arguments: starting X, starting Y, ending X, ending Y, and swipe duration. An emulator must be selected before calling it. It returns a bool indicating whether the swipe succeeded.
Example: swipe from (100, 100) to (200, 200) on emulator 2 over 500 ms.
Mumu().select(2).adb.swipe(100, 100, 200, 200, 500)
# or
Mumu().select(2).adb.swipe(100, 100, 200, 200) # default is 500 msExample: swipe from (100, 100) to (200, 200) on emulators 2, 4, and 6 over 500 ms.
Mumu().select(2, 4, 6).adb.swipe(100, 100, 200, 200, 500)This method accepts one argument (the text to input). An emulator must be selected before calling it. It returns a bool indicating whether the input succeeded.
Example: type Hello World on emulator 2.
Mumu().select(2).adb.input_text('Hello World')Example: type Hello World on emulators 2, 4, and 6.
Mumu().select(2, 4, 6).adb.input_text('Hello World')This method accepts one argument (the key to simulate). An emulator must be selected before calling it. It returns a bool indicating whether the key event succeeded.
Example: simulate the HOME key on emulator 2.
Mumu().select(2).adb.key_event(3)Example: simulate the HOME key using the key constants this project provides.
from mumu.constant import AndroidKey
Mumu().select(2).adb.key_event(AndroidKey.KEYCODE_HOME)Example: simulate volume up on emulators 2, 4, and 6.
from mumu.constant import AndroidKey
Mumu().select(2, 4, 6).adb.key_event(AndroidKey.KEYCODE_VOLUME_UP)This method accepts two arguments: the local file path and the emulator file path. An emulator must be selected before calling it. It returns a bool indicating whether the upload succeeded.
When the upload fails, a warning is emitted.
Example: push the local file C:\test.txt to /sdcard/test.txt on emulator 2.
Mumu().select(2).adb.push(r'C:\test.txt', '/sdcard/test.txt')Example: push the local file C:\test.txt to /sdcard/test.txt on emulators 2, 4, and 6.
Mumu().select(2, 4, 6).adb.push(r'C:\test.txt', '/sdcard/test.txt')This method accepts two arguments: the local file path and the file name on the emulator. An emulator must be selected before calling it. It returns a bool indicating whether the upload succeeded.
When emulator file name is None, the local file name is used automatically.
Example: push the local file C:\test.txt to the Download directory on emulator 2.
Mumu().select(2).adb.push_download(r'C:\test.txt')Example: push the local file C:\test.txt to the Download directory on emulators 2, 4, and 6 and rename it to test1.txt.
Mumu().select(2, 4, 6).adb.push_download(r'C:\test.txt', 'test1.txt')This method accepts two arguments: the emulator file path and the local file path. An emulator must be selected before calling it. It returns a bool indicating whether the download succeeded.
When the download fails, a warning is emitted.
Example: pull /sdcard/test.txt from emulator 2 to local C:\test.txt.
Mumu().select(2).adb.pull('/sdcard/test.txt', r'C:\test.txt')This method accepts one argument (the app's package name). An emulator must be selected before calling it. It returns a bool indicating whether the clear succeeded.
If the package name is invalid, an exception is raised.
Example: clear app data on emulator 2.
Mumu().select(2).adb.clear('com.miHoYo.Yuanshen')This class exposes GUI automation for the emulator, e.g. driving operations via image, coordinate, or text matching.
Prerequisite: install the opencv-python library, e.g. pip install opencv-python.
Live frame capture supports two backends:
mumu_sdk(recommended): uses MuMu's official high-performance screenshot API; usually faster.scrcpy: a compatibility backend; requiresscrcpy-client(pip install scrcpy-client).
This method accepts three arguments:
handle: callback for processing frames.backend:auto/mumu_sdk/scrcpy, defaultauto.fps: only takes effect withmumu_sdk; the capture frame rate, default30.
When backend='auto', mumu_sdk is preferred and falls back to scrcpy automatically if it is unavailable.
The handle callback takes two arguments, frame and mumu, representing the frame and the current emulator object.
frame is a numpy array and can be processed directly with opencv methods.
mumu is the current emulator object with only the current emulator selected (thread-isolated; you can call its API directly).
Example: process frames from emulator 2.
def handle(frame, mumu):
# do something
print('Received frame from emulator:', mumu.core.utils.get_vm_id())
Mumu().select(2).auto.create_handle(handle)Example: process frames from emulators 2, 4, and 6.
def handle(frame, mumu):
# do something
print('Received frame from emulator:', mumu.core.utils.get_vm_id())
Mumu().select(2, 4, 6).auto.create_handle(handle)Example: force the MuMu SDK and set the frame rate.
Mumu().select(2).auto.create_handle(handle, backend='mumu_sdk', fps=60)Example: force the scrcpy backend.
Mumu().select(2).auto.create_handle(handle, backend='scrcpy')This method accepts two arguments, frame and path, and saves the emulator frame.
Example: save a frame to C:\test.png.
def handle(frame, mumu):
mumu.auto.save(frame, r'C:\test.png')
Mumu().select(2).auto.create_handle(handle)Example: save a frame from emulator 3 to 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)This method accepts 4 arguments: haystack, needle, confidence, and grayscale, and searches for an image inside a frame.
confidence is the similarity threshold, in the range 0-1, default 0.8.
grayscale toggles grayscale matching; default False.
Example: find the image C:\test.png inside a frame.
def handle(frame, mumu):
# do something
print('Received frame from emulator:', mumu.core.utils.get_vm_id())
pos = mumu.auto.locateOnScreen(frame, r'C:\test.png')
if pos:
print('Image found:', pos)
else:
print('Image not found')This method accepts 4 arguments: haystack, needle, confidence, and grayscale, and searches for an image inside a frame.
confidence is the similarity threshold, in the range 0-1, default 0.8.
grayscale toggles grayscale matching; default False.
def handle(frame, mumu):
# do something
print('Received frame from emulator:', mumu.core.utils.get_vm_id())
pos = mumu.auto.locateCenterOnScreen(frame, r'C:\test.png')
if pos:
print('Image center found:', pos)
else:
print('Image not found')This method accepts 4 arguments: haystack, needle, confidence, and grayscale, and searches for an image inside a frame.
confidence is the similarity threshold, in the range 0-1, default 0.8.
grayscale toggles grayscale matching; default False.
def handle(frame, mumu):
# do something
print('Received frame from emulator:', mumu.core.utils.get_vm_id())
pos = mumu.auto.locateAllOnScreen(frame, r'C:\test.png')
if pos:
print('Images found:', pos)
else:
print('Image not found')This method accepts one argument, box, and returns the center of the box as (x, y).
box is a tuple of 4 elements: top-left x, top-left y, bottom-right x, and bottom-right y.
def handle(frame, mumu):
# do something
print('Received frame from emulator:', mumu.core.utils.get_vm_id())
pos = mumu.auto.locateOnScreen(frame, r'C:\test.png')
if pos:
print('Image found:', pos)
x, y = mumu.auto.center(pos)
print('Center:', x, y)
else:
print('Image not found')Listen for frames from emulator 3. When test.png appears, print "Found", along with the current time and the emulator ID, and then go back to the home screen.
def handle(frame, mumu: Mumu):
if mumu.auto.locateOnScreen(frame, './test.png', confidence=0.75, grayscale=True):
print("Found", time.time(), 'on emulator', mumu.core.utils.get_vm_id())
mumu.androidEvent.go_home()
Mumu().select(3).auto.create_handle(handle)Author: wlkjyy
Mail: wlkjyy@vip.qq.com
WeChat: laravel_debug