Application Operations¶
In this chapter, you will learn how to install, start, and close apps, grant or revoke app permissions, disable or enable apps, and replay any Activity (schemes, Activities) including unexported ones.
Installing Apps¶
You need to prepare an APK file for installation. Single Android APK and Split APK (e.g., xapk) are supported.
Single APK¶
For a single APK file, use the following procedure:
>>> session = d.create_install_session()
>>> session.write("/path/to/file.apk")
session: 2033102247
name: "base.apk"
writtenBytes: 5130176
totalBytes: 5130176
>>> session.commit()
session: 2033102247
package: "com.example.apk"
legacyStatus: 1
statusMessage: "INSTALL_SUCCEEDED: Session installed"
finished: true
committed: true
progress: 1
success: true
>>>
Split APK (e.g., XAPK)¶
For multi‑APK apps, you may need to first extract the bundle. After extraction, you will typically see a file set like the following:
➜ apk_temp/ $ ls -l
total 350720
-rw-rw-r-- 1 root root 86M 1 26 1970 com.some.package.apk
-rw-rw-r-- 1 root root 772K 1 26 1970 config.ar.apk
-rw-rw-r-- 1 root root 68M 1 26 1970 config.arm64_v8a.apk
-rw-rw-r-- 1 root root 676K 1 26 1970 config.de.apk
-rw-rw-r-- 1 root root 478K 1 26 1970 config.en.apk
Then install them as follows. Usually you need to install the base APK, language packs, and native library APKs.
>>> session = d.create_install_session()
>>> session.write("com.example.app.apk", name="com.example.app.apk")
session: 1137194135
name: "com.example.app.apk"
writtenBytes: 89661970
totalBytes: 89661970
>>> session.write("config.de.apk", name="config.de.apk")
session: 1137194135
name: "config.de.apk"
writtenBytes: 692633
totalBytes: 90354603
>>> session.write("config.arm64_v8a.apk", name="config.arm64_v8a.apk")
session: 1137194135
name: "config.arm64_v8a.apk"
writtenBytes: 70978318
totalBytes: 161332921
>>> session.write("config.xxhdpi.apk", name="config.xxhdpi.apk")
session: 1137194135
name: "config.xxhdpi.apk"
writtenBytes: 6266292
totalBytes: 167599213
>>> session.commit()
session: 1137194135
package: "com.example.app"
legacyStatus: 1
statusMessage: "INSTALL_SUCCEEDED: Session installed"
finished: true
committed: true
progress: 0.900000036
success: true
>>>
If any error occurs during installation, an exception will be raised directly, for example when no base APK is provided for a split APK install:
>>> session = d.create_install_session()
>>> session.write("config.de.apk", name="config.de.apk")
session: 1658145271
name: "config.de.apk"
writtenBytes: 692633
totalBytes: 692633
>>> session.commit()
Traceback (most recent call last):
File "<console>", line 1, in <module>
....
raise self.remote_exception(exception)
lamda.exceptions.InstallPackageFailed: INSTALL_FAILED_INVALID_APK: Full install must include a base package
Session Parameters¶
Use specific session creation parameters to enable overwrite install, downgrade install, auto-grant permissions, installation to a specific user, etc.
You can use these parameters when creating a session as shown below:
session = d.create_install_session(request_downgrade=True)
Other Cases¶
Some systems may intercept the installation process or pop up app‑scanning dialogs such as Google Play Protect. In such cases you may want to automate the handling to complete the installation. You can do that.
commit provides a background installation mode, where you can continue without waiting and manually query the installation status.
>>> session = d.create_install_session()
>>> session.write("/path/to/file.apk")
session: 1079135981
name: "base.apk"
writtenBytes: 5130176
totalBytes: 5130176
>>> session.commit(wait=False)
session: 1079135981
status: -2147483648
legacyStatus: -2147483648
statusMessage: "Commit sent"
committed: true
progress: 0.8
>>> session.status()
session: 1079135981
package: "com.example.app"
status: -2147483648
legacyStatus: -2147483648
statusMessage: "Commit sent"
committed: true
progress: 0.900000036
>>> session.status()
session: 1079135981
package: "com.example.app"
legacyStatus: 1
statusMessage: "INSTALL_SUCCEEDED: Session installed"
finished: true
committed: true
progress: 1
success: true
This way, after installation starts, you can use other code to handle dialogs that appear during installation. Using a Watcher for automatic clicking is also a feasible approach.
List Installed Apps¶
Get information about all apps installed on the device.
d.enumerate_installed_apps()
>>> d.enumerate_installed_apps()
[packageName: "com.android.uwb.resources"
label: "System UWB Resources"
uid: 10110
enabled: true
system: true
versionName: "T-initial"
, packageName: "com.android.adservices.api"
label: "Android System"
uid: 10105
enabled: true
system: true
versionName: "14"
...
List Running Apps¶
Get information about currently running processes on the system.
d.enumerate_running_processes()
>>> d.enumerate_running_processes()
[packages: "com.android.launcher3"
processName: "com.android.launcher3"
uid: 10084
pid: 2360
label: "Quickstep"
, packages: "com.google.android.gms"
processName: "com.google.android.gms.persistent"
uid: 10123
pid: 2765
label: "Google Play services"
, packages: "com.instagram.android"
processName: "com.instagram.android"
uid: 10150
pid: 5529
label: "Instagram"
...
>>> result = d.enumerate_running_processes()
>>> print(result[0].processName)
com.android.launcher3
Get App by Name¶
Get an app instance by its common name (without knowing the package ID).
app = d.get_application_by_name("微信")
Get App by Package Name¶
Get an app instance using its package ID.
app = d.application("com.tencent.mm")
Get Foreground App¶
Get the app instance currently running in the foreground.
app = d.current_application()
Get Multi‑Profile App¶
Get an instance of an app installed under a separate user profile (typically distinguished by user and with uid 999).
app = d.application("com.my.app", user=999)
Start App¶
Start this app.
app.start()
Stop App¶
Force‑stop this app.
app.stop()
Check Foreground Status¶
Check whether the app is currently in the foreground.
app.is_foreground()
Get App Information¶
Retrieve information about the app, such as version, etc.
app.info()
>>> app.info()
packageName: "com.android.settings"
uid: 1000
enabled: true
processName: "com.android.settings"
sourceDir: "/system/product/priv-app/Settings/Settings.apk"
dataDir: "/data/user_de/0/com.android.settings"
firstInstallTime: 1230739200000
lastUpdateTime: 1230768000000
versionCode: 1276
versionName: "10"
>>> result = app.info()
>>> print(result.processName)
'com.android.settings'
Check if Installed¶
Check whether the app is already installed on the device.
app.is_installed()
Uninstall App¶
Uninstall the app from the device.
app.uninstall()
Launch an Activity¶
You can replay system‑level Activities to start any Activity of any application. Available parameters are shown below. Note that extras support only boolean, int, short, long, double, float, and string types.
For the definition of flags, refer to the documentation developer.android.com/reference/android/content/Intent.
from lamda.const import *
d.start_activity(action="*", category="*", component="*", extras={"boolean": False, "int": 1, "string": "abc", "float": 1.123}, flags=FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_CLEAR_TASK, data="*", debug=False)
Now, using the “get recent activities” API as an example, you can replay the last system Activity directly with:
activity = d.get_last_activities(count=5)[-1]
d.start_activity(**activity)
If you want to launch an activity in a multi‑profile app, the following call will replay the Activity into the user 999 profile:
d.start_activity(**activity, user=999)
Some examples for reference: the following call will dial the 10000 customer service number.
d.start_activity(action="android.intent.action.CALL", data="tel:10000")
The following call will launch the Settings app, which is essentially equivalent to starting the app directly.
d.start_activity(action="android.intent.action.MAIN", category="android.intent.category.LAUNCHER", component="com.android.settings/.Settings")
The next call launches the Settings app in debug mode. If you have ever seen Waiting for debugger, this may be useful to you. Of course, your device or app must be debuggable. The only difference from the previous call is the extra debug parameter.
d.start_activity(action="android.intent.action.MAIN", category="android.intent.category.LAUNCHER", component="com.android.settings/.Settings", debug=True)
This call will take you directly to the certificate settings page.
d.start_activity(action="com.android.settings.TRUSTED_CREDENTIALS")
List App Permissions¶
This API lists all permission names declared by the app.
app.permissions()
>>> app.permissions()
['android.permission.REQUEST_NETWORK_SCORES', 'android.permission.WRITE_MEDIA_STORAGE', 'android.permission.WRITE_EXTERNAL_STORAGE', 'android.permission.READ_EXTERNAL_STORAGE', 'android.permission.WRITE_SETTINGS',...]
Grant App Permission¶
This API grants a system permission to the app. You should use it before the app is started; granting permissions while the app is running and requesting them will not automatically take effect.
from lamda.const import *
app.grant(PERMISSION_READ_PHONE_STATE, mode=GrantType.GRANT_ALLOW)
This is equivalent to providing the full permission string directly:
app.grant("android.permission.READ_PHONE_STATE", mode=GrantType.GRANT_ALLOW)
The mode parameter of the grant method also supports GrantType.GRANT_DENY, which explicitly denies the permission, and GrantType.GRANT_IGNORE. GRANT_IGNORE is special: it grants the permission to the app but the app cannot actually use it; for example, if an app requests the camera and you use this parameter, the camera preview may remain black.
Revoke App Permission¶
This API revokes a granted permission. You should also call it before the app starts.
from lamda.const import *
app.revoke(PERMISSION_READ_PHONE_STATE)
Check if Granted¶
This API checks whether a certain permission has been properly granted to the app.
from lamda.const import *
app.is_permission_granted(PERMISSION_READ_PHONE_STATE)
Clear App Cache¶
This API clears the app’s cache data, usually without adverse effects.
app.clear_cache()
Clear App Data¶
This API clears the app’s data. Note that this will erase all app data, causing account information etc. to be lost.
app.reset()
Get Launch Activity¶
You can query the launch Activity (entry Activity) of the app with this API.
app.query_launch_activity()
>>> app.query_launch_activity()
{'action': 'android.intent.action.MAIN', 'component': 'com.android.settings/com.android.settings.Settings', 'categories': ['android.intent.category.LAUNCHER']}
Enable App¶
This API enables a previously disabled app. Once enabled, you can use the app normally again.
app.enable()
Disable App¶
This API disables an app. A disabled app will not appear in the app list and cannot be used until enabled. This can temporarily or permanently freeze the app; it cannot auto‑start. When many apps are installed on the device, you can appropriately disable those you currently do not need to reduce system resource usage.
app.disable()