有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JAVAlang.NoSuchFieldError:类“Ljava/lang/Integer”中没有“I”字段“value”或者它的超类Android 10

我收到了一封信。所以我必须将客户端的安卓库集成到我的Xamarin表单项目中。该库帮助应用程序连接到物联网设备。由于库方法具有以下特征,我决定编写一个java包装器来简化参数并创建一个aar文件。之后,我以本机方式绑定aar,并将其用作项目中的dll

需要注意的是,Xamarin中的问题仅在编译目标为>;10.否则,它可以正常工作。我的猜测是latest Updates to non-SDK interfaces broke the application

库标题:

public static native int ReadParams(String token, StringBuilder serial, StringBuilder ssid, StringBuilder password, StringBuilder sensor, Integer keepAlive);

问题是: 当从本机安卓应用程序中调用该方法时,该方法工作正常,但是由于Xamarin表单中的以下错误而崩溃。崩溃在Java包装器的下面一行

紧急救援线:

StringBuilder strSerial = new StringBuilder();
StringBuilder strssid = new StringBuilder();
StringBuilder strpassword = new StringBuilder();
StringBuilder strsensor = new StringBuilder();
Integer keepAlive = new Integer(0);
//Crash on below line
int response = EPM002Lib.ReadParams(token, strSerial, strssid, strpassword, strsensor, keepAlive);

堆栈跟踪:

--- End of managed Java.Lang.IncompatibleClassChangeError stack trace --- java.lang.NoSuchFieldError: no "I" field "value" in class "Ljava/lang/Integer;" or its superclasses at com.esong.lib.EPM002Lib.ReadParams(Native Method) at com.sensorwa.config.configdemo.SquareSdkhelper.ReadParams(SquareSdkhelper.java:32)

我了解更多关于EPM002Lib内部功能的信息。ReadParams-params会有所帮助,但是,该库似乎可以与本机安卓应用程序一起使用(即使是在针对安卓 10编译时)。请随时询问更多信息或提供建议。谢谢你的帮助😄


共 (2) 个答案

  1. # 1 楼答案

    您依赖的是一个不应该依赖的实现细节

    现在它坏了,你可以保留这两部分

  2. # 2 楼答案

    我使用Android Aarch64编译器编译了此文件:

    #include <jni.h>
    
    int access_field(JNIEnv *env, jobject obj) {
        jclass cls_Integer = (*env)->FindClass(env, "Ljava/lang/Integer;");
        jfieldID fid_Integer_value = (*env)->GetFieldID(env, cls_Integer, "value", "I");
        return (*env)->GetIntField(env, obj, fid_Integer_value);
    }
    
    int access_method(JNIEnv *env, jobject obj) {
        jclass cls_Integer = (*env)->FindClass(env, "Ljava/lang/Integer;");
        jmethodID mid_Integer_value = (*env)->GetMethodID(env, cls_Integer, "intValue", "()I");
        return (*env)->CallIntMethod(env, obj, mid_Integer_value);
    }
    

    这将为access_field生成以下代码:

    int access_field(JNIEnv *env, jobject obj) {
       0:   d10103ff    sub sp, sp, #0x40
       4:   a9037bfd    stp x29, x30, [sp,#48]
       8:   9100c3fd    add x29, sp, #0x30
       c:   90000008    adrp    x8, 0 <access_field>
      10:   91000108    add x8, x8, #0x0
      14:   90000002    adrp    x2, 0 <access_field>
      18:   91000042    add x2, x2, #0x0
      1c:   90000003    adrp    x3, 0 <access_field>
      20:   91000063    add x3, x3, #0x0
      24:   f81f83a0    stur    x0, [x29,#-8]
      28:   f81f03a1    stur    x1, [x29,#-16]
        jclass cls_Integer = (*env)->FindClass(env, "Ljava/lang/Integer;");
      2c:   f85f83a9    ldur    x9, [x29,#-8]
      30:   f9400129    ldr x9, [x9]
      34:   f9401929    ldr x9, [x9,#48]
      38:   f85f83a0    ldur    x0, [x29,#-8]
      3c:   aa0803e1    mov x1, x8
      40:   f90007e2    str x2, [sp,#8]
      44:   f90003e3    str x3, [sp]
      48:   d63f0120    blr x9
      4c:   f9000fe0    str x0, [sp,#24]
        jfieldID fid_Integer_value = (*env)->GetFieldID(env, cls_Integer, "value", "I");
      50:   f85f83a8    ldur    x8, [x29,#-8]
      54:   f9400108    ldr x8, [x8]
      58:   f9417908    ldr x8, [x8,#752]
      5c:   f85f83a0    ldur    x0, [x29,#-8]
      60:   f9400fe1    ldr x1, [sp,#24]
      64:   f94007e2    ldr x2, [sp,#8]
      68:   f94003e3    ldr x3, [sp]
      6c:   d63f0100    blr x8
      70:   f9000be0    str x0, [sp,#16]
        return (*env)->GetIntField(env, obj, fid_Integer_value);
      74:   f85f83a8    ldur    x8, [x29,#-8]
      78:   f9400108    ldr x8, [x8]
      7c:   f9419108    ldr x8, [x8,#800]
      80:   f85f83a0    ldur    x0, [x29,#-8]
      84:   f85f03a1    ldur    x1, [x29,#-16]
      88:   f9400be2    ldr x2, [sp,#16]
      8c:   d63f0100    blr x8
      90:   a9437bfd    ldp x29, x30, [sp,#48]
      94:   910103ff    add sp, sp, #0x40
      98:   d65f03c0    ret
    
    
    }
    

    对于access_method而言:

    int access_method(JNIEnv *env, jobject obj) {
      9c:   d10103ff    sub sp, sp, #0x40
      a0:   a9037bfd    stp x29, x30, [sp,#48]
      a4:   9100c3fd    add x29, sp, #0x30
      a8:   90000008    adrp    x8, 0 <access_field>
      ac:   91000108    add x8, x8, #0x0
      b0:   90000002    adrp    x2, 0 <access_field>
      b4:   91000042    add x2, x2, #0x0
      b8:   90000003    adrp    x3, 0 <access_field>
      bc:   91000063    add x3, x3, #0x0
      c0:   f81f83a0    stur    x0, [x29,#-8]
      c4:   f81f03a1    stur    x1, [x29,#-16]
        jclass cls_Integer = (*env)->FindClass(env, "Ljava/lang/Integer;");
      c8:   f85f83a9    ldur    x9, [x29,#-8]
      cc:   f9400129    ldr x9, [x9]
      d0:   f9401929    ldr x9, [x9,#48]
      d4:   f85f83a0    ldur    x0, [x29,#-8]
      d8:   aa0803e1    mov x1, x8
      dc:   f90007e2    str x2, [sp,#8]
      e0:   f90003e3    str x3, [sp]
      e4:   d63f0120    blr x9
      e8:   f9000fe0    str x0, [sp,#24]
        jmethodID mid_Integer_value = (*env)->GetMethodID(env, cls_Integer, "intValue", "()I");
      ec:   f85f83a8    ldur    x8, [x29,#-8]
      f0:   f9400108    ldr x8, [x8]
      f4:   f9408508    ldr x8, [x8,#264]
      f8:   f85f83a0    ldur    x0, [x29,#-8]
      fc:   f9400fe1    ldr x1, [sp,#24]
     100:   f94007e2    ldr x2, [sp,#8]
     104:   f94003e3    ldr x3, [sp]
     108:   d63f0100    blr x8
     10c:   f9000be0    str x0, [sp,#16]
        return (*env)->CallIntMethod(env, obj, mid_Integer_value);
     110:   f85f83a8    ldur    x8, [x29,#-8]
     114:   f9400108    ldr x8, [x8]
     118:   f940c508    ldr x8, [x8,#392]
     11c:   f85f83a0    ldur    x0, [x29,#-8]
     120:   f85f03a1    ldur    x1, [x29,#-16]
     124:   f9400be2    ldr x2, [sp,#16]
     128:   d63f0100    blr x8
     12c:   a9437bfd    ldp x29, x30, [sp,#48]
     130:   910103ff    add sp, sp, #0x40
     134:   d65f03c0    ret
    

    主要区别在于ldr x8调用中使用的偏移量。这些是JNIEnv中函数指针表的偏移量,更具体地说:

    • GetFieldID位于偏移量752处
    • GetIntField位于偏移量800处
    • GetMethodID位于偏移量264处
    • CallIntMethod位于偏移量392处

    另一个区别是传递给GetIntFieldGetMethodID的签名,该签名在链接器时被注入。我转储的对象文件尚未链接,因此那里有伪指令。它是第四个参数,因此在寄存器x3中传递

    因此,总而言之,您需要执行以下操作:

    • 在库中的某个位置查找字符串"()I"的地址或将其添加到字符串表中
    • 您需要找到访问java.lang.Integer#value的所有位置
    • 替换ldr x8调用前blr x8中的两个函数指针偏移量(752->;264;800->;392)
    • 查找更改x3的代码,并将其改为指向"()I"

    祝你好运