如何使用 Python 脚本从 Android 设备提取已安装应用的包名及标题
在开发和管理 Android 应用的过程中,有时我们需要批量获取设备上已安装应用的信息,如包名和应用标题。这在进行自动化测试、应用管理和监控等场景中非常有用。本文将介绍如何使用 Python 脚本实现这一目标。
我们的目标是编写一个 Python 脚本,它可以连接到 Android 设备(通过 ADB),列出设备上所有已安装的应用,并获取每个应用的包名和应用标题。最终,脚本将把结果保存到一个文本文件中。
- Python:确保你已经在你的机器上安装了 Python。
- ADB (Android Debug Bridge):用于与 Android 设备通信。
- aapt2:Android Asset Packaging Tool 的最新版本,用于从 APK 文件中提取元数据。
确保 ADB 和 aapt2 已经配置好环境变量,或者你知道它们的确切路径。
首先,我们需要获取设备上所有已安装应用的包名。这可以通过调用 ADB 命令 `pm list packages` 实现。
对于每个包名,我们需要获取其对应的 APK 文件路径。这可以通过调用 ADB 命令 `dumpsys package <package_name>` 并解析输出来实现。
一旦我们有了 APK 文件路径,就可以使用 adb 来拉取 APK 文件到本地,用于后续操作。
APK 文件拉取到本地之后,就可以使用 aapt2 来提取应用的元数据,包括应用标题。
以下是完整的 Python 脚本,它实现了上述功能:
#!/usr/bin/python
import subprocess
import os
import time
import tempfile
def get_apk_path(adb_path, package_name):
# 获取应用的 APK 文件路径
app_info = subprocess.check_output([adb_path, 'shell', 'dumpsys', 'package', package_name]).decode()
apk_path_line = next((line for line in app_info.splitlines() if 'path:' in line), None)
if apk_path_line:
start_index = apk_path_line.find("path:") + len("path:")
end_index = len(apk_path_line)
apk_path = apk_path_line[start_index:end_index].strip()
return apk_path
return ""
def is_non_system_apk(apk_path):
# 检查 APK 是否位于非系统区域
return apk_path.startswith('/data/app')
def pull_apk(adb_path, apk_path, temp_dir):
# 使用 adb pull 将 APK 文件拉取到本地
local_apk_path = os.path.join(temp_dir, os.path.basename(apk_path))
pull_command = [adb_path, 'pull', apk_path, local_apk_path]
subprocess.check_call(pull_command)
return local_apk_path
def get_app_title(aapt2_path, adb_path, apk_path, temp_dir):
# 使用 aapt2 获取应用的标题
if not is_non_system_apk(apk_path):
return "(system app)"
local_apk_path = pull_apk(adb_path, apk_path, temp_dir)
try:
# 确保文件完全写入磁盘
time.sleep(1)
if os.path.exists(local_apk_path):
dump_command = [aapt2_path, 'dump', 'badging', local_apk_path]
output = subprocess.check_output(dump_command, stderr=subprocess.STDOUT).decode()
title_line = next((line for line in output.splitlines() if "application-label:" in line), None)
if title_line:
title_start = title_line.find("application-label:'")
title_end = title_line.find("'", title_start + len("application-label:'"))
if title_end != - 1:
title = title_line[title_start + len("application-label:'"):title_end].strip()
return title
else:
return ""
except subprocess.CalledProcessError as e:
return f"Error extracting title from {local_apk_path} : {e.output.decode()} "
finally:
# 清理临时文件
if os.path.exists(local_apk_path):
os.remove(local_apk_path)
return ""
def get_installed_apps_with_titles(aapt2_path, adb_path):
# 获取所有已安装应用的包名
installed_apps = subprocess.check_output([adb_path, 'shell', 'pm', 'list', 'packages']).decode()
packages = [line[8:] for line in installed_apps.splitlines()]
# 对于每一个包名,获取应用的标题
apps_with_titles = []
with tempfile.TemporaryDirectory() as temp_dir:
for pkg in packages:
apk_path = get_apk_path(adb_path, pkg)
if apk_path and is_non_system_apk(apk_path):
title = get_app_title(aapt2_path, adb_path, apk_path, temp_dir)
apps_with_titles.append((pkg, title))
print(f"Processing {pkg} : Title is ' {title} '")
return apps_with_titles
aapt2_path = "/Mqtt/Program/android-sdk-linux/build-tools/34.0.0/aapt2"
adb_path = "/Mqtt/Program/android-sdk-linux/platform-tools/adb"
output_file = "/Beauty/SoftwareDevelop/placeholder.89/note.yws/runlog/2024.8.26.4/processed_packages.pg.txt"
# 获取所有已安装的应用包名及其对应的标题
apps_with_titles = get_installed_apps_with_titles(aapt2_path, adb_path)
# 将应用的标题和包名写入文件
with open(output_file, "w") as file:
for pkg, title in apps_with_titles:
file.write(f" {title or '(no title)' } ( {pkg} ) \n ")
通过上述步骤,我们可以有效地从 Android 设备上提取已安装应用的包名和标题。
希望这篇博客对你有所帮助!如果你在实施过程中遇到任何问题,或者有其他建议,请随时联系我。
- ADB: `/Mqtt/Program/android-sdk-linux/platform-tools/adb`
- aapt2: `/Mqtt/Program/android-sdk-linux/build-tools/34.0.0/aapt2`
- 输出文件: `/Beauty/SoftwareDevelop/placeholder.89/note.yws/runlog/2024.8.26.4/processed_packages.pg.txt`
/data/app/~~IkkTz0nAiUwrxlpwCN1zlg==/com.lk.sqxbw.mi-nJFEPNwtLuC-zuT6mIxYYg==/base.apk: 1 file pulled, 0 skipped. 37.7 MB/s (79140041 bytes in 2.002s)
Processing com.lk.sqxbw.mi: Title is '
水枪小霸王
'
/data/app/~~ph1MzfhzMufr4292onmLhA==/com.lenovo.leos.appstore-cfXui6Fo-iFE0iuAB4BsxA==/base.apk: 1 file pulled, 0 skipped. 37.9
MB/s (71803037 bytes in 1.809s)
Processing com.lenovo.leos.appstore: Title is '
应用商店
'
/data/app/~~z9yrkVaO63_iiR8x49kKeA==/com.moregold.dddj-Nt_OfgOKRzOzDr3GBKF3ug==/base.apk: 1 file pulled, 0 skipped. 38.5 MB/s (76637109 bytes in 1.896s)
Processing com.moregold.dddj: Title is '
点点多金
'
/data/app/~~dFY-Yeffx_3H5mHbn7ICPw==/com.stupidbeauty.simageview-3aZ0cx94eiO58c3Q8X88Zg==/base.apk: 1 file pulled, 0 skipped. 37.2 MB/s (10928442 bytes in 0.280s)
Processing com.stupidbeauty.simageview: Title is 'SImageView'
Push Service (com.lenovo.lsf.device)
恐怖贞子来了 (com.xph.kbzzll.mi)
DingDing (com.alibaba.android.rimet)
X (com.twitter.android)
薪人薪事 (com.client.xrxs.com.xrxsapp)
Your opinionsHxLauncher: Launch Android applications by voice commands