mcpField
G
gplay-preflight

gplay-preflight

github.com/tamtom测试与质量52167 次安装13 周前更新
代码仓库

关于 gplay-preflight

gplay-preflight 是用于上传前扫描本地 Android APK 和 AAB 构建产物的技能,可离线检查发布风险、权限、原生库、机密信息及可选的商店元数据,并提供 CI 门禁和 JSON 报告。

主要功能

  1. 01离线扫描 APK 和 AAB
  2. 02检查清单与权限
  3. 03检查原生库和大小
  4. 04检测机密信息与 SDK
  5. 05可选验证商店元数据
  6. 06JSON 报告与 CI 门禁

适用场景

  1. 01上传前检查 Android 构建产物
  2. 02在 CI 中阻止存在严重问题的发布
  3. 03检查商店文案和图片素材
  4. 04使用 JSON 工具分析发现项

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/tamtom/gplay-cli-skills --skill gplay-preflight

安装后在 Claude Code 中输入/gplay-preflight确认已加载。

详细介绍

gplay preflight — 离线构建扫描

gplay preflight 会检查本地 .aab 或 .apk 并报告发现的问题。它不会调用任何 API,也不需要凭据,因此可以在任何机器、任何 CI 任务中运行,甚至在构件首次接触 Play 之前就能使用。

请在运行 gplay validate(需要身份验证并会调用 API)和上传之前运行它。它可以发现 Play 可能在数小时后才会拒绝的问题,或导致用户设备安装失败的问题。

前提条件

  • 磁盘上有已构建的 .aab 或 .apk。
  • 无需其他条件。不需要运行 gplay auth login,不需要 --package,也不需要网络。

基本用法

# Scan a bundle
gplay preflight --file app-release.aab

# Also validate the store listing in the same pass
gplay preflight --file app-release.aab --listings-dir ./fastlane/metadata/android

# Machine-readable
gplay preflight --file app-release.aab --output json --pretty

# See what scanners exist
gplay preflight --list-scanners

preflight 如何读取构建

preflight 会完整解码 AndroidManifest.xml——APK 使用二进制 AXML,App Bundle 使用 aapt2 protobuf——因此发现的问题反映的是实际的类型化属性值,而不是基于子字符串的猜测。

解读结果时,这一点很重要:如果某个属性指向资源引用(例如 android:debuggable="@bool/isDebug"),报告会标明无法静态确定,而不是标为 false。在这种情况下,不要将未发现问题视为不存在问题的证明。

激进的代码缩减可能会重命名或移除类,因此未检测到 SDK 并不能证明该 SDK 不存在。不过,检测到的匹配项具有较高置信度。

九个扫描器

每个扫描器都有一个 ID。可使用 --only 选择,或使用 --skip 排除(以逗号分隔)。

manifest

清单级别的正确性检查和阻止发布的标志。

  • android:debuggable="true" — 错误。发布了可调试构建。
  • android:testOnly="true" — 错误。Play 会直接拒绝上传。
  • 对于 targetSdk 31 及以上版本,包含 <intent-filter> 且未设置 android:exported 的组件 — 错误。这会导致 Android 12 及以上版本安装失败,而不是警告。启动器 Activity 不受此限制。
  • 设置了 grantUriPermissions 的已导出 <provider> — 错误。任何应用都可以访问已授权的 URI。
  • 在 targetSdk 34 及以上版本中,前台服务类型缺少对应权限 — Android 14 会在运行时抛出 SecurityException。dataSync 类型需要 FOREGROUND_SERVICE_DATA_SYNC。
  • usesCleartextTraffic="true" — 警告;存在 networkSecurityConfig 时降级为信息。
  • allowBackup、requestLegacyExternalStorage、包名和版本合理性检查。
permissions
  • 需要填写 Play 声明表单的受限权限:SMS 和通话记录组、MANAGE_EXTERNAL_STORAGE、ACCESS_BACKGROUND_LOCATION、QUERY_ALL_PACKAGES、SYSTEM_ALERT_WINDOW、BIND_ACCESSIBILITY_SERVICE、USE_FULL_SCREEN_INTENT、SCHEDULE_EXACT_ALARM 等。每条发现都附有 Play 政策文档链接。
  • 需要在 Data safety 中披露的敏感权限(信息级别)。
  • 旧版存储权限:targetSdk 为 30 及以上版本时,WRITE_EXTERNAL_STORAGE 未设置 maxSdkVersion;33 及以上版本时使用 READ_EXTERNAL_STORAGE。
  • 重复和已弃用的权限。
native_libs
  • 缺少 arm64-v8a — 错误。自 2019 年起,Play 要求支持 64 位。
  • 16 KB 内存页对齐,从实际 ELF 程序头中读取。targetSdk 为 35 及以上版本时为错误,低于 35 时为警告。使用 16 KB 页的 Android 15 设备无法加载未对齐的 .so 文件。
  • 存在 x86,但缺少 x86_64;或使用裸 armeabi。
  • 存在未剥离的 .debug_* / .symtab 节 — 浪费下载空间。
  • extractNativeLibs="true" — 安装占用空间更大。
metadata

需要指定 --listings-dir。 否则会跳过。预期使用 Fastlane 风格的目录结构(<dir>/<locale>/title.txt、<dir>/<locale>/images/...)。

  • 标题 ≤ 30 个字符,简短说明 ≤ 80 个字符,完整说明 ≤ 4000 个字符,版本说明 ≤ 500 个字符 — 按 Unicode 字符计数,而非字节。
  • 实际像素尺寸:图标 512×512,特色图片 1024×500,宣传图片 180×120,TV 横幅 1280×720。
  • 屏幕截图:每边至少 320px,最多 3840px,宽高比最高为 2:1;手机屏幕截图至少 2 张,每种设备外形最多 8 张,每张最大 8 MB。
secrets

错误:私钥块、AWS 访问密钥、Stripe sk_live_、GitHub 令牌、Slack 令牌和 Webhook、SendGrid 密钥、Google OAuth 客户端密钥、OpenAI/Anthropic 密钥、服务账号 JSON、随应用发布的密钥库(.jks、.keystore、.p12、.pfx、.pem、.ppk),以及 .git/ 或 .env 泄露。

警告:Google API 密钥(AIza…)和 JWT。

Google API 密钥有意归为警告而非错误。Android 应用会按设计嵌入 Maps 和 Firebase 密钥。正确做法是在 Cloud Console 中将密钥限制为仅适用于你的包名和签名证书,而不是从二进制文件中移除。不要建议用户删除密钥。

也会扫描 Dex 字节码,因此硬编码的字符串字面量也会被检测到。

billing

检测构建中是否包含第三方支付处理商(Stripe、Braintree、PayPal、Adyen、Razorpay……),单独存在时会发出警告;如果也存在 Play Billing,则会降级为提示。此外,还会标记已声明 com.android.vending.BILLING 但未实现计费功能的情况,以及未随包提供 Play Billing Library 的计费封装库(RevenueCat、Adapty、Qonversion)。

privacy

盘点 40 多种分析、归因和广告 SDK(提示)。核对 AD_ID 权限:当 targetSdk 为 33 或更高、存在广告/跟踪 SDK 但缺少该权限时发出警告,并提示相反的情况。

policy
  • targetSdkVersion 低于 Play 的最低要求。Google 年度上调要求时,如果新的 gplay 版本尚未发布,可通过 --min-target-sdk 覆盖。
  • 受限服务:无障碍服务、VPN、设备管理、通知监听器。
  • APK 与 AAB 上传格式。
size

下载大小预算(--max-size)、每个 dex 的预算(--max-dex)、dex 碎片化情况,以及按类别划分的载荷明细,并列出最大的条目。

CI 门禁

# Block only on hard blockers
gplay preflight --file app-release.aab --fail-on error

# Stricter: warnings fail too
gplay preflight --file app-release.aab --fail-on warning

# Narrow the gate to the scanners you care about
gplay preflight --file app-release.aab \
  --only manifest,permissions,native_libs,secrets \
  --fail-on warning

# Faster: skip the secrets scan on very large builds
gplay preflight --file app-release.aab --skip-secrets

退出代码:

代码含义
0没有达到或超过 --fail-on 级别的发现项
1存在达到或超过 --fail-on 级别的发现项

GitHub Actions:

- name: Offline preflight
  run: |
    gplay preflight \
      --file app/build/outputs/bundle/release/app-release.aab \
      --listings-dir fastlane/metadata/android \
      --fail-on error

JSON 输出

--output json 会输出完整报告:格式、包、版本代码和名称、最低/目标 SDK、各扫描器的运行状态,以及每条发现项的 check、severity、message、entry、hint 和(适用时)ref 政策链接。

# Just the errors
gplay preflight --file app.aab --output json | jq '[.findings[] | select(.severity=="error")]'

# Which scanners were skipped and why
gplay preflight --file app.aab --output json | jq '.scanners[] | select(.skipped)'

preflight 的定位

工具需要授权范围
gplay preflight否离线检查构件本身。Manifest、库、密钥、商品详情文件
gplay validate是发布就绪情况:本地检查,加上实时轨道和商品详情状态
gplay checks analyze是Google Checks 隐私/政策分析,在服务端异步执行
gplay release --dry-run是针对真实 edit 执行完整流程,并在提交前丢弃

按此顺序运行。preflight 成本最低,能发现最多问题。

Agent 行为

  • 在执行任何上传或发布命令之前,先运行 gplay preflight --file <artifact>,并在继续操作前报告发现项。
  • 只要存在元数据目录,就传入 --listings-dir;否则会跳过 metadata 扫描器,且不会报告商品详情问题。
  • 将 error 级别的发现项视为阻断项。除非用户明确同意,否则不要在存在此类问题时上传。
  • 不要只报告消息,还要报告 hint 和 ref 字段。提示会说明实际需要更改什么。
  • 不要建议删除密钥扫描器发现的 Google API 密钥,应建议限制其使用范围。
  • 如果无法解码 Manifest,或构建经过大量混淆,那么没有发现项并不能证明符合要求。应如实说明,不要声称构建没有问题。
  • 构造命令前,先通过 gplay preflight --help 确认可用标志。
  • --only 和 --skip 接受以逗号分隔的扫描器 ID;使用 gplay preflight --list-scanners 获取当前列表。

注意事项

  • preflight 只读取一次归档,并以有界分块的方式流式处理大型条目,因此处理大型包时内存占用保持稳定。
  • 扫描器 ID 保持稳定;供 JSON 消费者使用的发现项 check 名称会在不同版本间保留。
  • policy 扫描器的目标 API 下限是一个常量,Google 每年 8 月都会提高该值。如果该值看起来已过时,请传入 --min-target-sdk。

评论

支持 Markdown