Delphi Android项目中JNI_OnLoad未触发,如何手动调用?
手动调用JNI_OnLoad解决Delphi Android加载C++库的初始化问题
我之前帮开发者处理过类似的场景——Delphi加载Android原生SO库时,因为没有走Android原生的System.loadLibrary()流程,导致JNI_OnLoad这个关键的初始化函数不会自动触发。不过别担心,我们可以手动获取这个函数的地址并调用它,步骤如下:
1. 定义JNI_OnLoad的函数类型
首先在Delphi代码里声明和C端JNI_OnLoad匹配的函数类型,注意调用约定要用cdecl(因为C导出的函数默认是这个约定):
type TJNI_OnLoad = function(vm: PJNIJavaVM; reserved: Pointer): Integer; cdecl;
2. 加载SO库并获取JNI_OnLoad的地址
用Delphi的LoadLibrary加载你的SO库,然后通过GetProcAddress拿到JNI_OnLoad的函数指针:
var LibHandle: THandle; JNI_OnLoadFunc: TJNI_OnLoad; LJNIEnv: PJNIEnv; LJavaVM: PJNIJavaVM; begin // 加载你的C++库,注意替换成实际的库名 LibHandle := LoadLibrary('libyour_native_lib.so'); if LibHandle = 0 then Exit; // 获取JNI_OnLoad的函数地址 @JNI_OnLoadFunc := GetProcAddress(LibHandle, 'JNI_OnLoad'); if not Assigned(JNI_OnLoadFunc) then begin // 这里可以加日志提示函数找不到,可能是库没导出或者名字被混淆 FreeLibrary(LibHandle); Exit; end;
3. 获取JavaVM指针并调用JNI_OnLoad
JNI_OnLoad需要传入当前的JavaVM指针,我们可以通过Delphi Android框架提供的SharedActivity来获取JNIEnv,进而得到JavaVM:
// 获取当前的JNIEnv if not SharedActivity.GetJNIEnv(LJNIEnv) then begin FreeLibrary(LibHandle); Exit; end; // 从JNIEnv中获取JavaVM指针 if LJNIEnv^.GetJavaVM(LJNIEnv, @LJavaVM) <> JNI_OK then begin FreeLibrary(LibHandle); Exit; end; // 手动调用JNI_OnLoad,完成库的初始化 JNI_OnLoadFunc(LJavaVM, nil); end;
关键注意事项
- 函数导出问题:确保你的C库是用
extern "C"导出JNI_OnLoad的,否则C的名字修饰会让函数名变成 mangled 形式,GetProcAddress会找不到它。比如C++端的代码应该是:extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { // 你的初始化逻辑,比如注册Native方法 return JNI_VERSION_1_6; } - 调用时机:一定要在调用库中其他JNI相关函数之前调用
JNI_OnLoad,否则库的初始化没完成,后续调用可能会崩溃。 - 路径正确性:确保你的SO库放在Delphi Android项目的正确目录下(比如
libs/armeabi-v7a、libs/arm64-v8a等),否则LoadLibrary会加载失败。
这样操作后,你的C++库中的JNI_OnLoad就会被执行,里面的初始化逻辑(比如Native方法注册)也会生效,之后你就可以正常从Delphi调用库中的功能了。
内容的提问来源于stack exchange,提问作者bodam
相关产品推荐
相关产品推荐

