关于 gpc-preflight
GPC Preflight Scanner 是一项技能,用于发布前检查 Android 应用包和 APK 是否符合 Google Play 要求。它介绍九类扫描器、可配置的检查结果、签名一致性检查及 CI 用法。
主要功能
- 01扫描 AAB 和 APK 文件
- 02检查清单与权限
- 03检查原生库及对齐情况
- 04检测密钥和计费 SDK
- 05验证商店资料与政策
- 06通过 Play API 检查签名证书
适用场景
- 01上传至 Play 前发现政策问题
- 02在 CI 中依据扫描结果设发布门禁
- 03排查签名证书不一致
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yasserstudio/ gpc-skills --skill gpc-preflight安装后在 Claude Code 中输入/gpc-preflight确认已加载。
详细介绍
GPC 预检扫描器
使用场景
在任务涉及以下内容时使用此技能:
- 在上传到 Google Play 之前扫描 AAB 或 APK 文件
- 检查目标 SDK 版本是否合规
- 审核权限是否符合 Google Play 政策
- 验证是否支持 64 位原生库
- 扫描源代码中的硬编码密钥或凭据
- 检测非 Play 结算 SDK
- 检查商店商品详情元数据是否合规
- 基于政策合规性设置 CI/CD 质量门禁
快速参考
# Full scan (AAB or APK)
gpc preflight app.aab
gpc preflight app.apk
# With metadata and source scanning
gpc preflight app.aab --metadata fastlane/metadata/android --source app/src
# Specific scanners only
gpc preflight manifest app.aab
gpc preflight permissions app.aab
gpc preflight metadata ./metadata
gpc preflight codescan ./src
# CI mode
gpc preflight app.aab --fail-on error --json
9 个扫描器
| 扫描器 | 检查项 | 严重级别 |
|---|---|---|
| manifest | targetSdk >= 36(v0.9.79+)、debuggable、testOnly(自 v0.9.80 起从 <application> 元素读取)、cleartext、缺少 exported、FGS 类型、地理围栏前台服务(v0.9.65+) | critical/error/warning |
| permissions | 18 项受限权限、通讯录广泛访问、Health Connect 细粒度权限(v0.9.65+)、Data Safety 提醒 | critical/error/warning/info |
| native-libs | 64 位 ARM 合规性、ABI 检测、16KB 页面边界对齐(自 v0.9.80 起支持 AAB + APK;读取 4096 字节 ELF 标头;每次扫描最多 512 个库) | critical/warning |
| metadata | 商品详情字符数限制、截图、隐私政策 URL | error/warning |
| secrets | AWS 密钥、Google API 密钥、Stripe 密钥、私钥 | critical/warning |
| billing | Stripe、Braintree、PayPal、Razorpay SDK 检测 | warning |
| privacy | 跟踪 SDK、Advertising ID、数据收集交叉核对 | warning/info |
| policy | 家庭/COPPA、金融、健康、UGC、悬浮层 | warning/info |
| size | 每台设备的预计下载大小(AAB:仅计最大 ABI,不含 bundle 元数据或按需/快速跟进模块;APK:计整个文件)、大型原生库、大型资源 | warning/info |
配置(.preflightrc.json)
{
"failOn": "error",
"targetSdkMinimum": 36,
"maxDownloadSizeMb": 200,
"allowedPermissions": ["android.permission.READ_SMS"],
"disabledRules": ["cleartext-traffic"],
"severityOverrides": { "billing-stripe-sdk": "info" }
}
从 2026 年 8 月 31 日起,Google Play 上的所有新应用和更新都必须使用 API 级别 36(Android 16)。GPC preflight 在 v0.9.79 中将 targetSdkMinimum 默认值更新为 36,以符合此期限要求。
下载大小(v0.9.99+)
对于 AAB,size-over-limit 会按照 Google Play 分发 bundle 的方式,估算一台设备的下载内容:只计最大 ABI 的原生库,不包括 BUNDLE-METADATA/(调试符号、R8 映射文件)或 bundle 签名,也不包括按需模块、快速跟进模块或资源包。所有屏幕密度和语言仍会计入,因此估算值偏高。对于 APK,则计入整个文件。默认的 maxDownloadSizeMb 为 200,即 Play 在用户使用移动数据时显示大型下载对话框的大小阈值。在 v0.9.99 之前,计算会汇总整个 .aab,因此多 ABI 的 Flutter/React Native bundle 会被误报为实际下载大小的 3-4 倍(GH #116);如果旧版本遇到此问题,请升级,或添加 "disabledRules": ["size-over-limit"]。如需精确数值,请对 bundle 运行 bundletool get-size total。
native-libs-large(native-libs 扫描器)和 size-large-native 对 AAB 也同样按单个最大 ABI 计算。
APK 扫描: manifest 检查(manifest、permissions、policy、privacy 扫描器)目前仅针对 AAB 运行。APK 的二进制 XML manifest 尚无法解码,因此 APK 扫描会报告“Manifest could not be fully parsed”,并继续运行其余检查。若要全面检查,请扫描你准备上传的 AAB。
退出代码
0— 所有检查均已通过1— 运行时错误6— 发现项达到或超过--fail-on指定的严重级别
关键规则
| 规则 ID | 严重程度 | 内容 |
|---|---|---|
| targetSdk-below-minimum | 严重 | targetSdkVersion < 36 |
| debuggable-true | 严重 | android:debuggable="true" |
| testOnly-true | 严重 | android:testOnly="true" |
| missing-arm64 | 严重 | 仅有 32 位 ARM,不含 64 位 |
| missing-exported | 错误 | 带有 intent-filter 的组件未设置 exported 属性 |
| foreground-service-type-missing | 警告 | 应用请求了 FOREGROUND_SERVICE,但没有服务声明 foregroundServiceType(API 34+);仅报告一次(v0.9.99+,此前每个服务报告一个错误) |
| secret-aws-key | 严重 | 源代码中包含 AWS 访问密钥 |
| secret-stripe-key | 严重 | 源代码中包含 Stripe 密钥 |
| contacts-permission-broad | 警告 | READ_CONTACTS / WRITE_CONTACTS(v0.9.65+,2026 年 4 月政策) |
| geofencing-foreground-service | 警告 | 位置 FGS + ACCESS_BACKGROUND_LOCATION(v0.9.65+,2026 年 4 月政策) |
| health-connect-granular | 警告/信息 | READ_ALL_HEALTH_DATA;targetSdk >= 36 时为警告,否则为信息(v0.9.65+,2026 年 4 月政策) |
| policy-app-content-declaration | 信息 | 任何 FOREGROUND_SERVICE* 权限;提醒你在 Play Console -> Policy -> App content 中填写相应声明(v0.9.94+) |
| native-libs-16kb-unchecked | 警告 | 并非所有原生库都能检查 16 KB 对齐情况(v1.0.0-rc.1+) |
native-libs-16kb-unchecked(v1.0.0-rc.1+):读取器最多缓冲 512 个 .so 头文件,避免包含数千个原生库的应用包占用过多内存。当应用包中的库超过此数量时,对齐检查只会覆盖前 512 个,因此预检会明确提示,而不会让不完整的检查显示为通过。检查结果会说明跳过了多少个库。如需检查整个应用包,请使用 Android Studio 的 APK Analyzer,或在通用 APK 上运行 zipalign -c -P 16 -v 4 app.apk。大多数应用都不会遇到此规则。
操作流程
运行完整预检扫描
- 构建 AAB 或 APK:
./gradlew bundleRelease(APK 使用assembleRelease) - 运行:
gpc preflight app/build/outputs/bundle/release/app-release.aab或者对 APK 运行:gpc preflight app/build/outputs/apk/release/app-release.apk - 修复所有严重/错误级别的问题
- 添加
.preflightrc.json,以允许已批准的权限或禁用误报 - 重新运行,直到扫描通过
注意:扫描完成后,GPC 会提醒你 Android 开发者验证要求(2026 年 9 月 30 日起在 BR、ID、SG、TH 强制执行)。运行 gpc verify 查看详情。
从 v0.9.80 起,当扫描器被筛除时,结果 JSON 会包含 skippedScanners 数组(例如,因清单解析失败而跳过依赖清单的扫描器)。这取代了此前静默省略被跳过扫描器的行为。
签名密钥一致性(v0.9.66+)
gpc preflight signing # Check cert consistency across two most recent bundles
gpc preflight signing --json # JSON output for CI
gpc preflight signing --app com.example.app # Override package name
通过 Play API(generatedApks.list)比较你最近两个应用包版本的签名证书。需要身份验证(服务账号或 OAuth)。不匹配时退出码为 6(与其他预检阈值超限情况相同)。API 出错时退出码为 4。
这不是离线扫描。它会调用 Play API 创建一个 edit、列出应用包、获取版本代码最高的两个版本对应的生成 APK,比较 certificateSha256Fingerprint,然后删除该 edit。
2026 年 4 月政策规则(v0.9.65+)
针对 Google Play 2026 年 4 月 15 日的政策更新,新增了三条规则。合规截止日期:2026 年 5 月 15 日。
-
广泛访问联系人(
contacts-permission-broad):检测 READ_CONTACTS / WRITE_CONTACTS。Google 现在要求使用 Android Contact Picker,而不是广泛访问联系人。即使同时声明了这两项权限,也只会生成一条发现。拨号器/消息应用可通过allowedPermissions忽略此规则。 -
地理围栏前台服务(
geofencing-foreground-service):当服务的foregroundServiceType包含 "location",且应用声明了ACCESS_BACKGROUND_LOCATION时触发。Google 已将地理围栏从获批的前台服务使用场景中移除。对于合法的后台位置跟踪(导航、健身),可通过"disabledRules": ["geofencing-foreground-service"]忽略此规则。 -
Health Connect 细粒度权限(
health-connect-granular):检测READ_ALL_HEALTH_DATA。当targetSdk >= 36(Android 16 要求)时,严重级别为warning;否则为info。请改用细粒度权限,例如health.READ_STEPS、health.READ_HEART_RATE等。
应用内容声明提示(v0.9.94+)
只要 AAB 请求了任何 FOREGROUND_SERVICE* 权限,policy-app-content-declaration 就会以 info 严重级别触发,并列出相应权限。这是在提醒你:必须在 Play Console → Policy → App content 中完成匹配的“Foreground service permissions”声明,Google 才会接受发布。
为何只能提供提示:该声明存储在 Play Console 中,Publisher API 不会公开此信息,也无法从应用包中读取。Preflight 可以看到你的应用请求了这些权限,但无法判断你是否填写了表单。因此,无论 --fail-on 的设置如何,它都不会导致运行失败。
这与 foreground-service-type-missing 检查并不相同。 后者检查 <service> 元素上的 android:foregroundServiceType,这是调用 startForeground() 的服务必须满足的清单要求。即使所有服务都已正确指定类型,上传仍可能因缺少 Console 声明而被阻止——这正是添加此规则的原因。
如果声明不完整,上传会因 API_DECLARATION_REQUIRED 而失败(v0.9.94+)。在 v0.9.94 之前,同一问题会被报告为服务帐号权限问题,导致用户前往 Users and permissions,而不是 App content。
每次扫描只生成一条发现,而不是每项权限各生成一条。
修复漏报问题(v0.9.80)
v0.9.80 发布了四项扫描准确性改进:
-
testOnly属性来源:现在testOnly扫描器会从清单的<application>元素读取android:testOnly。此前它错误地从<manifest>根元素读取,导致即使在应用上设置了testOnly="true",检查也总是报告未发现问题。 -
16KB 对齐扫描器范围:现在 16KB 页面对齐扫描器除了检查 AAB,还会检查 APK 中的原生库。此前它只检查 AAB 构件,导致 APK 中的原生库未被扫描。
-
ELF 头读取大小:ELF 头读取器的读取大小从 256 字节增加到 4096 字节。对于某些原生库格式,小尺寸读取不足以完成检查,导致对齐检查被静默跳过。
-
结果中的
skippedScanners:通过skippedScanners禁用的扫描器(或因缺少输入而跳过的扫描器),现在会在扫描结果 JSON 的skippedScanners数组中报告。当扫描器未运行时,这样 CI 中便能清楚地看到。
添加到 CI 中
# GitHub Actions
- name: Preflight
run: gpc preflight app.aab --fail-on error --json > preflight.json
- name: Upload report
if: always()
uses: actions/upload-artifact@v4
with:
name: preflight-report
path: preflight.json
相关技能
gpc-release-flow— 预检通过后的上传和发布gpc-ci-integration— CI/CD 模式,包括预检关卡gpc-troubleshooting— 处理退出代码 6gpc-security— 凭据处理和密钥轮换