Android生产构建中Native Module 'BoundingBox'找不到的问题排查
Android生产构建找不到Native Module问题排查
问题描述
开发首个支持iOS和Android的Expo Native Module,iOS端运行正常,Android开发构建无问题,但生产构建打包后应用崩溃。通过adb logcat捕获到报错:
2024-12-08 20:49:20.531 29294-29339 ReactNativeJS com.identafly.preview E Error: Cannot find native module 'BoundingBox', js engine: hermes 2024-12-08 20:49:20.537 29294-29340 AndroidRuntime com.identafly.preview E FATAL EXCEPTION: mqt_native_modules Process: com.identafly.preview, PID: 29294 com.facebook.react.common.JavascriptException: Error: Cannot find native module 'BoundingBox', js engine: hermes, stack: requireNativeModule@1:688911
相关配置与代码
expo-module.config.json
{ "platforms": ["ios", "tvos", "android", "web"], "ios": { "modules": ["BoundingBoxModule"] }, "android": { "modules": ["expo.modules.boundingbox.BoundingBoxModule"] } }
JS模块层代码(modules/bounding-box/index.ts)
import { type BoundingBoxProps } from './src/BoundingBox.types'; // Import the native module. On web, it will be resolved to BoundingBox.web.ts // and on native platforms to BoundingBox.ts import BoundingBoxModule from './src/BoundingBoxModule'; const drawBoundingBox = (props?: BoundingBoxProps) => { if ( BoundingBoxModule && typeof BoundingBoxModule.drawBoundingBox === 'function' ) { BoundingBoxModule.drawBoundingBox(props?.boundingBox, props?.color); } else { console.error('drawBoundingBox method not found'); } }; export { BoundingBoxProps, drawBoundingBox };
Native模块引入代码(modules/bounding-box/src/BoundingBoxModule.ts)
import { requireNativeModule } from 'expo-modules-core'; // It loads the native module object from the JSI or falls back to // the bridge module (from NativeModulesProxy) if the remote debugger is on. export default requireNativeModule('BoundingBox');
差异分析与解决方案
开发与生产bundle的核心差异
- 模块打包策略:开发模式保留动态引用和调试逻辑,Native模块通过调试桥接(如
NativeModulesProxy)加载;生产模式下Hermes会做激进压缩和树摇,若模块注册逻辑未被正确识别,可能被误删或无法绑定。 - JSI vs 桥接模式:生产模式默认启用JSI直接调用Native模块,开发模式可能 fallback 到传统桥接。若Android端模块未正确注册到JSI,生产构建会找不到模块。
可能的问题点及修复方案
Android模块注册不完整
- 检查原生代码中
BoundingBoxModule是否实现ExpoModule接口,类上标注@ExpoModule注解且name参数与JS端调用的BoundingBox完全一致:@ExpoModule(name = "BoundingBox") public class BoundingBoxModule extends ExpoModule { // 模块实现逻辑 }
- 检查原生代码中
expo-module.config.json配置问题
- 确认Android模块全类名大小写与实际类一致(Java/Kotlin对包名大小写敏感),建议补充
package配置帮助Expo识别模块位置:"android": { "package": "expo.modules.boundingbox", "modules": ["expo.modules.boundingbox.BoundingBoxModule"] }
- 确认Android模块全类名大小写与实际类一致(Java/Kotlin对包名大小写敏感),建议补充
R8混淆导致模块被移除
- Android生产构建默认启用R8混淆,需在
proguard-rules.pro中添加规则保留模块类:-keep class expo.modules.boundingbox.BoundingBoxModule { *; } -keep class expo.modules.core.interfaces.ExpoModule { *; }
- Android生产构建默认启用R8混淆,需在
Tree Shaking误删模块引用
- 生产构建的Tree Shaking可能误将模块标记为未使用,可在JS端添加强制引用避免被摇掉:
// 在index.ts中补充 if (!__DEV__) { // 强制保留模块引用,防止Tree Shaking移除 BoundingBoxModule; }
- 生产构建的Tree Shaking可能误将模块标记为未使用,可在JS端添加强制引用避免被摇掉:
内容的提问来源于stack exchange,提问作者Phil Lucks
相关产品推荐
相关产品推荐

