【问题标题】:Invoke JNI_OnLoad from Delphi从 Delphi 调用 JNI_OnLoad
【发布时间】:2018-02-07 18:07:27
【问题描述】:

我有一个本地 c++ 库,我想在我的 delphi android 项目中使用它; 这是我想从 Delphi 代码部分调用它的重要部分:

#include <jni.h>
#include <android/log.h>

#define  LOG_TAG    "EmbJniTest"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)


JavaVM* gJavaVM = NULL;
//------------------------------------------------------------------------
jint JNI_OnLoad(JavaVM* aVm, void* aReserved)
{
 // cache java VM
 gJavaVM = aVm;
 JNIEnv* env;// latter on it'll be used as global var
 LOGI("JVM INIT");
 if (aVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
 {
  LOGI("Failed to get the environment");
  return -1;
 }
 return JNI_VERSION_1_6;
}

这是我加载 mylibrary 的 delphi 代码部分:

LIBNAME = 'libtest.so';


function try_load_dll:integer;
var libPath:system.string;
begin
  _status:= 0 ;
  libPath:=TPath.Combine(tpath.GetLibraryPath,libname);
  _status := LoadLibrary(PChar(libPath));
  result:=_Status;
  if( _status= 0 )then exit;
end;

问题是

JNI_OnLoad

从未被调用;我在 logcat 中看不到任何关于它的日志。

我读过 JNI_OnLoad 的调用是由 System.loadLibrary() 完成的。如果 你没有使用它来加载库,JNI_OnLoad 不会发生。

来自here 所以请无论如何我可以从我的delphi代码中调用它。

谢谢

【问题讨论】:

  • 你可以调用它,但你要为JavaVM* 传递什么?
  • @RichardCritten ,稍后我会将 JNIEnv* env 保存为全局变量,以便在我的原生库中的某些过程和函数中使用它
  • 只是想知道为什么 JNI_OnLoad 没有被调用,我看不到任何日志
  • @pskink,我没有 java 代码,只有我的原生 Lib 和 Delphi 作为消费者应用程序
  • @RemyLebeau,谢谢,除了在我的 delphi 代码中调用 JNI_OnLoad 函数之外,没有其他选择/解决方案了吗?

标签: android c++ delphi android-ndk


【解决方案1】:

只是想知道为什么 JNI_OnLoad 没有被调用

JNI_OnLoad() 通常由 Java JVM 调用,如果它是加载本机库的那个(即,当 Java 代码调用 System.loadLibrary() 时)。

由于您的示例中不是这种情况,这就是您的JNI_OnLoad() 未被调用的原因。你自己直接加载库,所以你必须自己打电话给JNI_OnLoad()

Embarcadero 在Embarcadero.Jni 单元中声明了一个TJNI_OnLoad 函数指针类型。使用GetProcAddress() 获取指向库导出的JNI_OnLoad() 函数的指针,并将该指针分配给TJNI_OnLoad 变量。然后你可以像调用任何其他函数一样调用JNI_OnLoad()

稍后我会将JNIEnv* env 保存为全局变量,以便在我的本地库中的某些过程和函数中使用它

JNI_OnLoad()JavaVM* 指针作为输入。调用JNI_OnLoad() 的人必须传入一个指向有效JavaVM 对象的指针。

Java JVM 通常会为您处理这些。但是,由于您自己加载库,因此必须自己调用JNI_OnLoad(),您必须从您的Delphi 代码中提供一个JavaVM 对象。而不是自己调用JNI_CreateJavaVM()应该能够使用 Delphi 的 RTL 在内部使用的相同的 JavaVM 对象 - RTL 的 System 单元中的 JavaMachine 指针(只需将其类型转换为PJavaVM,也在Embarcadero.Jni单元中声明)。

试试这个:

uses
   ..., Embarcadero.Jni

const
  LIBNAME = 'libtest.so';

function try_load_dll: THandle;
var
  libPath: string;
  OnLoadFunc: TJNI_OnLoad;
  hlib: THandle;
begin
  Result := 0;
  libPath := TPath.Combine(TPath.GetLibraryPath, libname);
  hlib := LoadLibrary(PChar(libPath));
  if hlib = 0 then Exit;
  @OnLoadFunc := GetProcAddress(hlib, 'JNI_OnLoad');
  if not Assigned(OnLoadFunc) then
  begin
    FreeLibrary(hlib);
    Exit;
  end;
  OnLoadFunc(PJavaVM(System.JavaMachine), nil);
  Result := hlib;
end;

【讨论】:

    猜你喜欢
    • 2016-07-24
    • 1970-01-01
    • 2023-03-18
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-15
    • 2012-05-04
    相关资源
    最近更新 更多