多 ABI CI 与符号管理:让 native 崩溃在线上也能还原
一个 NDK 模块能在你本机跑起来,不代表它能在所有目标设备上稳定运行。native 交付必须回答三个问题。
每个 ABI 都能构建吗
每个 ABI 都能打进包吗
线上 crash 能符号化回源码行吗
这就是多 ABI CI 和符号管理要解决的事。
为什么要多 ABI 构建
Android 设备有不同 ABI。
arm64-v8a:真机主力
armeabi-v7a:部分旧设备
x86_64:模拟器和部分设备
如果你只在 arm64-v8a 上构建过,x86_64 可能因为某个 Neon 头文件或汇编路径直接失败。
CI 要把 ABI 差异提前暴露。
CI 矩阵
最小矩阵:
buildType: Debug, RelWithDebInfo, Release
abi: arm64-v8a, x86_64
如果项目仍支持 32 位,再加入 armeabi-v7a。
Debug:快速发现编译和基础测试问题
RelWithDebInfo:用于 profiling 和符号化验证
Release:最终发布构建
符号文件是什么
Release 包里的 .so 通常会被 strip,去掉调试符号。这样包更小,但崩溃栈只剩地址。
unstripped .so 保留函数名和源码行信息。它不一定放进 APK,但必须归档。
线上 libplayer_core.so:用户设备上运行
符号 libplayer_core.so:CI 归档,用来还原 crash
两者必须来自同一次构建。
归档命名
建议按版本、commit、ABI 归档。
symbols/
1.4.0/
commit-abc123/
arm64-v8a/
libplayer_core.so
x86_64/
libplayer_core.so
再保存一份 manifest。
version=1.4.0
commit=abc123
ndkVersion=28.x
agpVersion=8.x
buildType=RelWithDebInfo
abi=arm64-v8a
没有 manifest,半年后你很难知道某个符号文件对应哪个线上包。
CI 检查项
每个 ABI 构建通过
APK/AAB 中包含期望 ABI
没有意外 ABI 混入
符号文件归档成功
llvm-nm -D 导出符号符合预期
llvm-readelf 检查 16KB 对齐
ndk-stack 用模拟 crash 能还原源码行
最后一条非常关键。不要等线上崩溃后才发现符号目录错了。
模拟符号化验证
流程:
构建带符号 native 库
制造一次测试 crash
收集 logcat crash dump
用 ndk-stack 指向 CI 归档符号目录
确认输出包含函数名和源码行
示例:
ndk-stack -sym symbols/1.4.0/commit-abc123/arm64-v8a -dump crash.txt
输出应能看到:
PlayerCrashTest::crashNow(PlayerCrashTest.cpp:18)
不要把符号文件丢进公开包
符号文件用于内部排障,不等于全部放进用户 APK。APK 里通常放 strip 后 .so,符号归档放 CI 产物或崩溃平台。
这样兼顾:
包体大小
实现细节保护
崩溃可还原
本章实验
给播放器模块建立一条最小 CI。
构建 arm64-v8a 和 x86_64
产出 APK
归档 unstripped .so
跑一次 ndk-stack 验证
输出 symbols-manifest.txt
验收标准:
任意 ABI 构建失败都会阻断发布
符号归档失败会阻断发布
模拟 crash 无法符号化会阻断发布
小白常见误解
第一,CI 构建成功不代表符号管理成功。能构建和能还原 crash 是两件事。
第二,符号文件不是越新越好,而是必须和线上包来自同一次构建。
第三,只测 arm64-v8a 不够。模拟器常用 x86_64,某些代码路径只有这个 ABI 会暴露。
第四,strip 后的线上 .so 不能替代 unstripped .so。没有未剥离符号,ndk-stack 很难还原源码行。
工程风险与观测
CI 要把 native 交付风险显式变成门禁。
ABI 缺失:阻断
16KB 检查失败:阻断
符号归档失败:阻断
模拟 crash 无法符号化:阻断
导出符号异常增加:观察或阻断
发布产物要记录。
app version
versionCode
commit
ndkVersion
agpVersion
abi list
symbols path
apk sha256
线上崩溃平台回传时,至少要能按这些维度聚合。
versionCode
ABI
device model
Android version
signal
native library
如果某次发布 crash rate 上升,先按 ABI 分组。native 问题经常只影响某一个 ABI。
本章结论
native 发布不能只看“本机能跑”。多 ABI CI 保证各类设备有对应产物,符号管理保证线上 crash 能回到源码。没有这两件事,NDK 模块上线后就是盲飞。