混淆后如何生成 mapping.txt 文件用于崩溃堆栈还原?
解读
国内面试里,这道题表面问“怎么拿到 mapping.txt”,实则考察候选人是否真正走过“发版→崩溃→还原”完整闭环。很多候选人只答“打开 minifyEnabled 就有”,却说不清:
- 构建链路中谁负责写 mapping.txt;
- 国内多渠道(华为、OPPO、小米、应用宝)各自加固再混淆时 mapping.txt 是否会被覆盖;
- 线上 Native 崩溃、Java 崩溃、Flutter 崩溃三种堆栈分别怎么用 mapping.txt 还原;
- 合规场景下 mapping.txt 含类名方法名,属于“可逆敏感信息”,如何存储与授权访问。
能把这四层讲清楚,才能体现工程化与安全意识。
知识点
- R8 / ProGuard 映射文件生成阶段:AGP 7.0+ 默认 R8,在
variant/minifiedTask 里通过-printmapping build/outputs/mapping/variant/mapping.txt输出。 - 多渠道包场景:加固厂商(腾讯乐固、阿里聚安全)会二次混淆,必须在其控制台上传原始 mapping.txt,否则还原结果错乱。
- 还原工具链:
- Java/Kotlin:Google 自带
retrace.jar/ AS 内置“Analyze Stack Trace”; - Native:需配合
ndk-stack与objdump,不受 mapping.txt 管辖; - Flutter:Dart AOT 使用
flutter symbolize,需app.android-arm64.symbols文件,与 mapping.txt 无关。
- Java/Kotlin:Google 自带
- 合规与 CI:mapping.txt 需进入受控仓库(Git LFS 或私有 Nexus),权限粒度到“仅崩溃平台可读取”,避免直接随 apk 分发。
- 自动化:在 CI 最后一步把 mapping.txt 作为产物上传到自研或第三方崩溃平台(如 Bugly、Firebase、Sentry),并打上与 apk 相同的
versionCode+git-sha标签,保证一对一匹配。
答案
- 在模块级
build.gradle开启混淆:
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
// 显式指定输出路径,防止被多渠道任务覆盖
mappingFileUploadEnabled true
}
}
}
R8 会在 app/build/outputs/mapping/release/mapping.txt 自动生成,无需手动写规则。
- CI 中固化产物:
./gradlew assembleRelease
# 拷贝并重命名,带上 git commit id
cp app/build/outputs/mapping/release/mapping.txt \
mapping-${VERSION_CODE}-${GIT_SHA}.txt
# 上传至内部 Maven 或崩溃平台
curl -F "file=@mapping-${VERSION_CODE}-${GIT_SHA}.txt" \
https://crash.mycompany.com/api/uploadMapping
- 线上收到堆栈后,用对应版本的 mapping.txt 本地还原:
retrace.sh -verbose mapping.txt crash.txt > readable.txt
或在 Android Studio 直接粘贴堆栈,选择“Add ProGuard Mapping”即可。
-
若使用加固,务必在加固后台再传一次原始 mapping.txt,并勾选“保留原混淆规则”,否则行号会偏移。
-
合规:mapping.txt 不随 apk 发布,不提交到公开仓库;访问需 OA 审批,存储加密 at rest,90 天后自动归档。
拓展思考
- 大型 App 采用“组件化 + 多 AAR” 时,每个 AAR 可能独立开启混淆,最终会出现多个 mapping.txt。此时需在 CI 里把所有 AAR 的 mapping 文件按模块名合并成
mapping-full.txt,再上传崩溃平台;否则堆栈里出现com.xxx.modulea.a.b时无法还原。 - 为了加快 CI,可在
gradle.properties里加android.enableR8.fullMode=false,牺牲少量优化换取 30% 构建时间,但 mapping.txt 体积会增大,需要评估崩溃还原平台的单文件大小限制。 - 未来 Google 强制 AAB 上架,Play 控制台自带“Deobfuscation files” 页签,国内厂商商店也在跟进。届时 mapping.txt 将像符号表一样成为强制上传项,团队需要提前把“上传-匹配-下载”做成 CLI 脚本,避免发版当天人工拖文件。
- 若项目混编 Kotlin 与 Java,Kotlin 的 inline 函数、lambda 名在 mapping.txt 里会出现
access$lambda-0这类符号,还原后仍不易读;可额外在proguard-rules.pro中加-keepattributes kotlin.Metadata并上传kotlin-module元数据,配合 Sentry 的 Kotlin 插件,能把 lambda 还原成可读的doLogin$lambda-0$impl形式,进一步缩短排障时间。