4.0 KiB
4.0 KiB
JNI函数名不匹配问题修复说明
问题描述
在代码重构过程中,将原生方法从MainActivity移动到DataManager类后,出现了以下错误:
Cannot resolve corresponding JNI function Java_com_example_cmake_1project_1test_DataManager_createStreamParser
问题原因
JNI函数命名规则
JNI函数名遵循以下格式:
Java_{包名}_{类名}_{方法名}
其中:
- 包名中的点(.)用下划线(_)替换
- 类名中的下划线用
_1替换
具体变化
重构前的JNI函数名(在MainActivity中):
Java_com_example_cmake_1project_1test_MainActivity_createStreamParser
Java_com_example_cmake_1project_1test_MainActivity_destroyStreamParser
Java_com_example_cmake_1project_1test_MainActivity_streamParserAppend
Java_com_example_cmake_1project_1test_MainActivity_streamParserDrainPackets
重构后的JNI函数名(在DataManager中):
Java_com_example_cmake_1project_1test_DataManager_createStreamParser
Java_com_example_cmake_1project_1test_DataManager_destroyStreamParser
Java_com_example_cmake_1project_1test_DataManager_streamParserAppend
Java_com_example_cmake_1project_1test_DataManager_streamParserDrainPackets
解决方案
方案1:回调接口模式(已实现)
通过创建回调接口,让DataManager通过MainActivity来调用原生方法,保持原有的JNI函数名。
实现步骤
- 创建回调接口
interface NativeMethodCallback {
fun createStreamParser(): Long
fun destroyStreamParser(handle: Long)
fun streamParserAppend(handle: Long, chunk: ByteArray)
fun streamParserDrainPackets(handle: Long): List<SensorData>?
}
- 修改DataManager构造函数
class DataManager(private val nativeCallback: NativeMethodCallback)
- MainActivity实现接口
class MainActivity : AppCompatActivity(), DataManager.NativeMethodCallback
- 保持原生方法在MainActivity中
// 原生方法声明 - 保持原来的JNI函数名
external fun createStreamParser(): Long
external fun destroyStreamParser(handle: Long)
external fun streamParserAppend(handle: Long, chunk: ByteArray)
external fun streamParserDrainPackets(handle: Long): List<SensorData>?
优势
- 保持原有的JNI函数名,无需修改C++代码
- 维持了代码重构的架构优势
- 清晰的职责分离
劣势
- 增加了接口依赖
- 稍微增加了代码复杂度
方案2:修改C++代码中的JNI函数名
如果您有权限修改C++代码,可以将C++中的JNI函数名改为新的名称。
需要修改的C++函数名
// 原来的函数名
JNIEXPORT jlong JNICALL Java_com_example_cmake_1project_1test_MainActivity_createStreamParser
// 改为
JNIEXPORT jlong JNICALL Java_com_example_cmake_1project_1test_DataManager_createStreamParser
优势
- 完全符合重构后的架构
- 无需额外的接口层
劣势
- 需要修改C++代码
- 可能影响其他依赖项目
推荐方案
推荐使用方案1(回调接口模式),原因如下:
- 无需修改C++代码:保持现有C++代码的稳定性
- 维持重构优势:仍然保持了代码的职责分离
- 向后兼容:如果将来需要,可以轻松切换到方案2
- 风险较低:不会引入新的编译或链接问题
修复后的架构
MainActivity (实现NativeMethodCallback)
↓
DataManager (通过回调调用原生方法)
↓
原生C++库 (保持原有JNI函数名)
注意事项
- JNI函数名一致性:确保Kotlin中的
external方法名与C++中的JNI函数名完全匹配 - 库加载:确保在
MainActivity的companion object中正确加载原生库 - 接口实现:MainActivity必须实现
NativeMethodCallback接口的所有方法 - 依赖注入:DataManager的构造函数现在需要传入回调接口实例
验证修复
修复完成后,您应该能够:
- 成功编译项目
- 不再看到JNI函数名不匹配的错误
- 保持原有的功能正常运行
- 享受重构后的代码结构优势