StupidBeauty
Read times:105Posted at:Mon Aug 26 09:00:41 2024 - no title specified

如何使用 Python 脚本从 Android 设备提取已安装应用的包名及标题

在开发和管理 Android 应用的过程中,有时我们需要批量获取设备上已安装应用的信息,如包名和应用标题。这在进行自动化测试、应用管理和监控等场景中非常有用。本文将介绍如何使用 Python 脚本实现这一目标。

1 目标

我们的目标是编写一个 Python 脚本,它可以连接到 Android 设备(通过 ADB),列出设备上所有已安装的应用,并获取每个应用的包名和应用标题。最终,脚本将把结果保存到一个文本文件中。

2 准备工具

- Python:确保你已经在你的机器上安装了 Python。

- ADB (Android Debug Bridge):用于与 Android 设备通信。

- aapt2:Android Asset Packaging Tool 的最新版本,用于从 APK 文件中提取元数据。

确保 ADB 和 aapt2 已经配置好环境变量,或者你知道它们的确切路径。

3 步骤 1: 获取已安装应用的列表

首先,我们需要获取设备上所有已安装应用的包名。这可以通过调用 ADB 命令 `pm list packages` 实现。

4 步骤 2: 获取应用的 APK 文件路径

对于每个包名,我们需要获取其对应的 APK 文件路径。这可以通过调用 ADB 命令 `dumpsys package <package_name>` 并解析输出来实现。

5 步骤 3: 使用 adbAPK 文件拉取到本地临时文件

一旦我们有了 APK 文件路径,就可以使用 adb 来拉取 APK 文件到本地,用于后续操作。

6 步骤 4: 使用 aapt2 提取应用标题

APK 文件拉取到本地之后,就可以使用 aapt2 来提取应用的元数据,包括应用标题。

7 完整脚本

以下是完整的 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 ")

8 结论

通过上述步骤,我们可以有效地从 Android 设备上提取已安装应用的包名和标题。

希望这篇博客对你有所帮助!如果你在实施过程中遇到任何问题,或者有其他建议,请随时联系我。

9 附录: 执行命令和环境

- 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`

10 运行过程中的部分输出

/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'

11 最终的记录文件中的部分内容

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 opinions

Your name:Email:Website url:Opinion content:
- no title specified

HxLauncher: Launch Android applications by voice commands