Redex 不能优化 C++ 原生代码,仅处理 APK 中的 .dex 字节码;C++ 优化需在 NDK 编译阶段通过 APP_OPTIM、CMake 标志、ABI 选择、符号管理等实现。

Redex 是什么,它真能优化 C++ 原生代码吗?
不能。Redex 只处理 Android APK 中的 .dex 字节码,也就是 Java/Kotlin 编译后的部分;C++ 原生代码(.so 文件)完全不在 Redex 的作用范围内。你用 Redex 跑一遍,lib/arm64-v8a/libnative.so 一点都不会变——连读都不会被读到。
常见错误现象:redex -c redex.config.json --sign -o app_optimized.apk app-debug.apk 执行成功,但 native 方法调用变慢、崩溃、或 UnsatisfiedLinkError 突然增多——这些和 Redex 无关,别浪费时间调它的配置。
那 C++ 代码该用什么优化?关键路径在哪?
Android 上 C++ 优化的核心在编译阶段,不是运行时重写。NDK 构建时的工具链、标志位、ABI 选择,直接决定最终 .so 的体积和性能。
-
APP_OPTIM := release必须启用,否则ndk-build或 CMake 默认走debug模式,禁用所有优化 - CMake 中要显式加
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -flto=thin"),-O3在某些 NDK 版本下反而导致符号丢失或崩溃 - 慎用
-fvisibility=hidden:它能减小符号表,但若 C++ 里用了JNI_OnLoad或导出函数给 Java 调用,漏标__attribute__((visibility("default")))就会找不到方法 - ABI 选
arm64-v8a单独打包比 fat APK 更省空间,但需确认 minSdkVersion ≥ 21,否则低版本设备直接 crash
Redex 和 C++ 有交集的地方只有一处:JNI 方法名混淆
Redex 默认会混淆 Java 层的 JNI 方法名(比如把 Java_com_example_Foo_nativeDoWork 改成 a),但如果你的 C++ 侧用的是 RegisterNatives 动态注册,且传入的 JNINativeMethod 数组里写的是旧名字,就会注册失败,Java 调用时抛 UnsatisfiedLinkError。
立即学习“C++免费学习笔记(深入)”;
解决办法只有两个:
- 在 Redex 配置中把所有 JNI 方法名加进
keep_rules,例如:"keep": [{"name": "Java_.*", "type": "method"}] - 改用静态注册(即函数名严格匹配
Java_XXX格式),并确保 Redex 的renamepass 不碰这些方法——这需要在passes里关掉InterDexPass或配keep_annotations
不配的话,Redex 优化完 APK,App 启动就卡在 JNI_OnLoad 之后的第一行 native 调用上,logcat 里只有模糊的 No implementation found for ...。
真正影响 C++ 性能的,是链接和符号剥离时机
NDK 提供的 strip 工具必须在签名前执行,且要分两步:先用 $NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-strip --strip-unneeded 剥离调试符号,再用 --strip-debug 留下行号信息用于 crash 分析——顺序反了或漏了,要么包体没变小,要么 tombstone 里全是 ???。
另一个坑:Gradle 的 android.ndk.debugSymbolLevel = 'FULL' 会自动解压 .so 到 build/intermediates/ndk/debug/symbols,但如果你手动运行了 strip,这个目录里的文件不会同步更新,上传 symbol 时就对不上栈帧。
所以,构建流程里只要涉及 .so 修改,就得确保符号路径、stripped 文件、mapping 文件三者严格对应——这点比 Redex 配置难 debug 得多。











