java - Delphi 使用 Android Jni 包装器中的过程

标签 java android delphi firemonkey-fm3

您好,我已经使用 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 已构建并编译(使用 cygwin 进行 NDK 构建)并与我的 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;

但总是出现相同的异常和错误,我什至尝试获取

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

同样的错误。

最佳答案

您的 Delphi 声明需要与底层 C 声明相匹配,但当前在以下三个方面不匹配:

  1. 正如 Remy 指出的,您使用的是封装 Java 类 java.lang.jobjectJObject JNI Bridge 接口(interface)类型(来自 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

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

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

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

关于java - Delphi 使用 Android Jni 包装器中的过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39575233/

相关文章:

java - 递归方法中ArrayList的状态

java - JQgrid 中列之间的粗体线

delphi - 如何设置 StringGrid 单元格边框的格式

Android Espresso 辅助功能检查失败

delphi - 检查目录是否可读

delphi - 如何从 IOTAProject 获取主源文件名?

java - 如何通过 JMX 监控 spring-boot 应用程序?

java - 在特写车牌图像上使用 JavaANPR

java - 在新 Activity 中查看和下载壁纸时遇到问题

android - 是否有任何带有 fragment 的android zxing库的教程