【问题标题】:Delphi consume a procedure from an Android Jni wrapperDelphi 使用来自 Android Jni 包装器的过程
【发布时间】:2016-09-19 14:08:02
【问题描述】:

您好,我使用 C 创建了一个 Android 类,它执行一些操作。 在这些程序中,我想使用这个:(仅用于 Delphi 测试)

JNIEXPORT void Java_Test_Project_Decode(JNIEnv* env, jclass clazz,jbyteArray dataIn, jbyteArray dataOut)
{
    jsize len = (*env)->GetArrayLength(env, dataIn);
    LOGV("JNI call Decode test dataIn Size = %d",len);

 jbyte *pByteIn = (*env)->GetByteArrayElements(env, dataIn, 0);
 jbyte *pByteOut = (*env)->GetByteArrayElements(env, dataOut, 0);


 *pDataOut = *pDataIn;  pDataIn++;  pDataOut++;


*pDataOut = *pDataIn;  pDataIn++;  pDataOut++;
*pDataOut = *pDataIn;  pDataIn++;  pDataOut++;

 // some routines
 (*env)->ReleaseByteArrayElements(env, dataOut, pByteOut, 0);
(*env)->ReleaseByteArrayElements(env, dataIn, pByteIn, 0);

}

当然,我的 testlib.so 是构建和编译的(NDK-build using cygwin)并与我的 Delphi 项目一起部署。

在我的 Delphi Firemonkey 客户端中,我以这种方式使用此过程:

Java_Test_Project_Decode:procedure(PEnv: PJNIEnv; Obj:JObject;dataIn:Pointer;DataOut:Pointer); cdecl;

当然是在我加载我的库之后:

Procedure LoadMyLib();
begin
FMyLib := LoadLibrary(PChar(LibFolder + LibTest));
  if FMyLib = 0 then
  begin
   Exit;
  end
     else 
          begin
          Java_Test_Project_Decode:=GetProcAddress(FMyLib,'Java_Test_Project_Decode');

             if not assigned (Java_Test_Project_Decode) then
               begin
                Exit; // Java_Test_Project_Decode procedure not loaded
               end else
                     begin
                   // OK Java_Test_Project_Decode procedure loaded
                    end;
        end;
end;

然后我使用程序:

Procedure TestMyProcedure (ADataIn: pointer; ASize: integer);
var 
ADataOut:Pointer;
begin
// ADataIn pointer is not empty 
Java_Test_Project_Decode(PEnv,Obj,ADataIn,ADataOut);
end;

但是在这里我得到一个异常并且应用程序崩溃了。

谁能帮我解决这个问题?

谢谢。

更新: 我可以按如下方式消除ADataOut

JNIEXPORT void Java_Test_Project_Decode(JNIEnv* env, jclass clazz,jbyteArray dataIn)
    {
        jsize len = (*env)->GetArrayLength(env, dataIn);
        LOGV("JNI call Decode test dataIn Size = %d",len);

     jbyte *pByteIn = (*env)->GetByteArrayElements(env, dataIn, 0);

     // some routines
    (*env)->ReleaseByteArrayElements(env, dataIn, pByteIn, 0);

    }

还有我的 Delphi 声明:

Java_Test_Project_Decode:procedure(PEnv: PJNIEnv; Obj:JObject;dataIn:Pointer); cdecl;

Procedure TestMyProcedure (ADataIn: pointer; ASize: integer);

    begin
    // ADataIn pointer is not empty 
    Java_Test_Project_Decode(PEnv,Obj,ADataIn);
    end;

但总是有同样的异常和错误,我什至试图得到 ​​p>

jsize len = (*env)->GetArrayLength(env, dataIn);
    LOGV("JNI call Decode test dataIn Size = %d",len);

同样的错误。

【问题讨论】:

  • ADataOut in TestMyProcedure() 未初始化,但 Java_Test_Project_Decode() 正在尝试访问和写入它。 Java_Test_Project_Decode() 要求 ADataInADataOut 是指向有效 Java 字节数组的指针,该数组的大小至少为 2 个元素。
  • @RemyLebeau,我可以在 Delphi 和 Java 程序中消除ADateOut,但仍然得到相同的异常和错误。虽然ADataIn 不是空的并且已初始化
  • 请编辑您的问题以显示更新后的代码。
  • @RemyLebeau 我更新了我的代码只是为了获取 DataIn 大小并记录它,但总是出现相同的错误和异常
  • 在 Android 上,Delphi 有一个 JObject 接口,它与 JNI 的 JObject 类型是分开的。确保在函数声明中使用 JNI 类型。

标签: java android delphi firemonkey-fm3


【解决方案1】:

您的 Delphi 声明需要与底层的 C 声明相匹配,目前它在三个方面没有做到这一点:

  1. 正如 Remy 指出的,您使用的是封装了 Java 类 java.lang.jobjectJObject JNI Bridge 接口类型(来自 RTL 单元 Androidapi.JNI.JavaTypes.pas),而不是类型 JNIObject(来自RTL 单元 Androidapi.Jni.pas),相当于 JNI 类型jobject。然而,这几乎是无关紧要的......
  2. 您的底层 C 方法使用 jclass 参数来暗示它是静态/类方法,但您的 Delphi 导入声明正在尝试使用 jobject 等效项,从而导致不匹配。它应该声明一个 JNIClass 类型的参数。
  3. 您的底层 C 方法使用 jbytearray JNI 参数类型,但您的 Delphi 声明使用类型 Pointer。相反,您应该使用与jbytearray 等效的Delphi,即JNIByteArray

只有当双方的所有参数和调用约定直接匹配时,调用才会成功。

在一个稍微相关的说明中,告知读者 .so 库是如何在 Delphi 项目中部署的以及您在运行时用于访问它的路径表达式可能会有所帮助,因为这可能远非如此清除。

为了执行类似的实验,我有一个 .so 文件,我将部署管理器设置为部署到 assets\internal\ 部署文件夹。这意味着我可以使用 TPath.Combine(TPath.GetDocumentsPath, LibName) 从 Android 应用代码中引用库文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多