Skip to content

Inspecting an APK

Everything on this page reads the decoded AndroidManifest.xml and, where needed, the resource table. The examples assume an opened APK:

from apk_info import APK

apk = APK("app.apk")
use apk_info::Apk;

let apk = Apk::new("app.apk")?;

Triage

print(f"Package:    {apk.get_package_name()}")
print(f"Version:    {apk.get_version_name()} ({apk.get_version_code()})")
print(f"SDK:        min {apk.get_min_sdk_version()}, target {apk.get_target_sdk_version()}")
print(f"Label:      {apk.get_application_label()}")
print(f"Debuggable: {apk.get_application_debuggable()}")
print(f"Backup:     {apk.get_application_allow_backup()}")
print(f"Multidex:   {apk.is_multidex()}")
print(f"ABIs:       {apk.get_supported_abis()}")
let package = apk.get_package_name().unwrap_or_default();
println!("Package:    {package}");
println!(
    "Version:    {} ({})",
    apk.get_version_name().unwrap_or_default(),
    apk.get_version_code().unwrap_or_default()
);
println!(
    "SDK:        min {}, target {}",
    apk.get_min_sdk_version().unwrap_or_default(),
    apk.get_target_sdk_version()
);
println!(
    "Label:      {}",
    apk.get_application_label().unwrap_or_default()
);
println!("Debuggable: {:?}", apk.get_application_debuggable());
println!("Backup:     {:?}", apk.get_application_allow_backup());
println!("Multidex:   {}", apk.is_multidex());
println!("ABIs:       {:?}", apk.get_supported_abis());
apk-info show app.apk

Output of the Python version for apkstest.apk (Rust prints Options with {:?}):

Package:    io.github.delvinru.apkstest
Version:    1.0.7 (7)
SDK:        min 21, target 35
Label:      APKS Test
Debuggable: None
Backup:     None
Multidex:   False
ABIs:       ['x86_64']

Boolean manifest attributes come back as they are written: "true", "false", or None when the attribute is absent, so you can tell an explicit android:debuggable="false" from a missing one.

get_supported_abis() lists the ABIs found under lib/. For XAPK / APKM / APKS files it also includes the ABIs of config.<abi>.apk splits.

Is it launchable?

An app is launchable when an activity (or activity alias) handles MAIN with the LAUNCHER or INFO category. get_main_activities() follows the same rules as Android's ApplicationPackageManager: activity aliases count, and activities with android:enabled="false" are skipped. get_main_activity() returns the first one.

activities = apk.get_main_activities()
if not activities:
    print("not launchable: no MAIN + LAUNCHER activity")
for activity in activities:
    print(f"adb shell am start -n {apk.get_package_name()}/{activity}")
let mut activities = apk.get_main_activities().peekable();
if activities.peek().is_none() {
    println!("not launchable: no MAIN + LAUNCHER activity");
}
for activity in activities {
    println!("adb shell am start -n {package}/{activity}");
}
adb shell am start -n io.github.delvinru.apkstest/.MainActivity

You get activity names as written in the manifest, so they may be relative (.MainActivity). am start -n accepts both forms.

Device targets

targets = [
    name
    for name, matches in [
        ("TV", apk.is_leanback()),
        ("Wear OS", apk.is_wearable()),
        ("Android Automotive", apk.is_automotive()),
        ("ChromeOS", apk.is_chromebook()),
        ("Android XR", apk.is_xr()),
    ]
    if matches
]
print(f"Targets: {', '.join(targets) or 'phone / tablet'}")
print(f"Features: {sorted(apk.get_features())}")
let targets: Vec<&str> = [
    ("TV", apk.is_leanback()),
    ("Wear OS", apk.is_wearable()),
    ("Android Automotive", apk.is_automotive()),
    ("ChromeOS", apk.is_chromebook()),
    ("Android XR", apk.is_xr()),
]
.into_iter()
.filter_map(|(name, matches)| matches.then_some(name))
.collect();
println!("Targets: {targets:?}");
Method True when <uses-feature> declares
is_leanback() android.software.leanback or android.hardware.type.television
is_wearable() android.hardware.type.watch
is_automotive() android.hardware.type.automotive
is_chromebook() android.hardware.type.pc
is_xr() android.software.xr.api.spatial or android.software.xr.api.openxr

Any manifest attribute

Getters exist for the common attributes. For everything else, get_attribute_value(tag, name) returns the attribute of the first matching tag, and get_all_attribute_values(tag, name) returns it for every matching tag. Pass attribute names without the android: prefix.

# any attribute of the first matching tag, by name without the "android:" prefix
print(apk.get_attribute_value("application", "networkSecurityConfig"))
print(apk.get_attribute_value("application", "usesCleartextTraffic"))

# every value of an attribute across all matching tags
print(apk.get_all_attribute_values("uses-permission", "name"))
println!(
    "{:?}",
    apk.get_attribute_value("application", "networkSecurityConfig")
);
let permissions: Vec<&str> = apk
    .get_all_attribute_values("uses-permission", "name")
    .collect();
println!("{permissions:?}");

Resource references

Many manifest values are references like @string/app_name. Getters such as get_application_label() resolve them through resources.arsc. For anything else, use get_resource_value():

# getters resolve resource references for you...
print(apk.get_application_label())
print(apk.get_application_icon())

# ...and get_resource_value resolves any other reference
print(apk.get_resource_value("@string/app_name"))
println!("{:?}", apk.get_application_label());
println!("{:?}", apk.get_resource_value("@string/app_name"));
APKS Test
res/drawable-xxhdpi-v4/icon.png
APKS Test

File resources resolve to their path inside the archive. Release builds often shorten these paths (for example res/7j.png), so don't expect res/mipmap-*/ic_launcher.png to exist.

If resources.arsc is missing or corrupted on purpose, parsing still succeeds: references stay unresolved, and you can still read the manifest, DEX files and signatures.

The full manifest

with open("AndroidManifest.xml", "w") as f:
    f.write(apk.get_xml_string())
std::fs::write("AndroidManifest.xml", apk.get_xml_string())?;
apk-info axml app.apk > AndroidManifest.xml

The output is the decoded XML with resource references resolved, the same as apk-info axml prints.