安装时模块正常但按需动态模块Native库加载异常咨询
Native C++ Android应用本地化动态模块问题
背景
我正在对一个基于Native C的Android应用做本地化,核心代码均为C编写,所有文本通过编译宏控制(例如LANG_JP对应日语)。
我创建了名为module_jp的按需动态模块,在其build.gradle中添加了额外的C++编译参数:
// module_jp's build.gradle plugins { id 'com.android.dynamic-feature' } android { ... defaultConfig { ... externalNativeBuild { cmake { cppFlags "-fno-rtti -DLUTF8 -DLANG_JP" // 此处添加LANG_JP编译宏 } } }
同时编写了独立的CMakeLists.txt用于生成libnative-activity-jp.so库:
// module_jp's CMakeLists.txt ... add_library( # 设置库名称 native-activity-jp 指定为共享库 SHARED ... ... target_include_directories( native-activity-jp PRIVATE ${PLAYCORE_LOCATION}/include ) ... target_link_libraries( # 关联依赖库 native-activity-jp ...
应用启动时提供语言选择功能,在LanguageSelectionActivity中根据用户选择加载对应Native库:
// LanguageSelectionActivity // 启动Native Activity进入主流程 private void StartMainActivity(String LanguageCode) { if (LanguageCode.equals("en")) System.loadLibrary("native-activity"); else System.loadLibrary("native-activity-" + LanguageCode); // 初始化Intent启动主Native Activity Intent intent = new Intent(getApplicationContext(), NativeActivity.class); startActivity(intent); finish(); }
问题现象
本地测试完全正常,选择日语可正确显示翻译文本;但上传至Google封闭测试(Alpha)和内部应用共享后,日志显示module_jp已安装且libnative-activity-jp.so已加载,却仍显示英文内容,推测base模块的libnative-activity.so被优先加载。
已完成的排查
- 通过adb备份并提取文件,确认
libnative-activity-jp.so已正确安装在设备的data/data/<包名>/splitcompat/##/native-libraries目录 - 使用提取出的库进行本地测试,可正常显示日语翻译
- 将模块交付类型改为「安装时」后,在Google测试渠道中可正常工作
咨询问题
- 即使未调用
System.loadLibrary("native-activity"),base模块的Native库是否仍会被优先加载? - 为何模块设为「安装时」正常,设为「按需」就异常?
解答
问题1:base模块Native库是否会自动加载
是的。Android系统在启动NativeActivity时,会根据Manifest中关联的默认Native库(即base模块的libnative-activity.so)自动触发加载流程,无需手动调用System.loadLibrary。
这种自动加载的优先级高于手动加载的动态模块库,系统会先加载base库的符号,后续加载的libnative-activity-jp.so中同名符号无法覆盖已加载的base库符号,最终显示英文文本。
问题2:安装时正常、按需异常的原因
- 当模块设为「安装时」交付时,动态模块的Native库会被放置到与base模块库相同的标准Native库目录(
/data/app/<包名>/lib/<abi>/)。手动加载libnative-activity-jp.so后,系统后续尝试加载base库时会发现同名符号已存在,不会重复加载base库符号,因此能正常显示日语。 - 当模块设为「按需」交付时,动态模块的Native库会被存放在SplitCompat的隔离目录(
splitcompat/##/native-libraries)。系统加载base库时从标准路径读取,此时动态模块库的符号处于隔离空间,无法覆盖已加载的base库符号,最终仍使用base库的英文文本。
内容的提问来源于stack exchange,提问作者pleasebugmenot.mrg
相关产品推荐
相关产品推荐

