1

您好,我已经使用 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);

    }

和我的德尔福声明:

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;

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

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

同样的错误。

4

1 回答 1

0

您的 Delphi 声明需要与底层 C 声明相匹配,它目前在以下三个方面没有:

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

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

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

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

于 2016-09-21T21:08:22.320 回答