AndroidStudio调用第三方so库

背景

        最近公司设备换了新的触摸屏(为I2C接口),该触摸屏有个app,app中可以显示触摸屏固件的版本。我需要做的是在自己的app中读取到触摸屏固件版本。

        反编译了apk,得到了源码,发现对方app是通过jni调用so库的方式获取到的触摸屏固件版本。所以我可以从apk中拿到这个第三方so库,然后用我们自己的app去调用so库中的方法得到固件版本。这里记录一下在实现过程中遇到的问题和解决方案。

1.导入so库

        第三方so库的文件名为libegalaxapijni.so,将该文件放在libs目录下,如果没有该文件夹,需要手动创建。

        并在app的build.gradle中设置

android {
    ...
    defaultConfig {
        ...
        ndk {
            // 设置支持的SO库架构
            abiFilters 'armeabi-v7a'
        }
    }
}

2.调用jni方法

         创建一个工具类如图,用来调用jni方法

public class TouchScreenJNIUtil {
    // 加载库文件
    static {
        System.loadLibrary("egalaxapijni");
    }

    static native int getFWVersion(byte[] paramArrayOfbyte);

}
(1)找不到引用的so库问题解决方案1

        当我调用TouchScreenJNIUtil.getFWVersion()时报错

System.err: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.logdemo-2/base.apk"],nativeLibraryDirectories=[/data/app/com.example.logdemo-2/lib/arm, /vendor/lib, /system/lib]]] couldn't find "libegalaxapijni.so"

        这是由于找不到引用的so库导致的。 解决方法

android {
    ...
    defaultConfig {
        ...
        ndk {
            // 设置支持的SO库架构
            abiFilters 'armeabi-v7a'
        }
    }

    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}
(1.1)找不到引用的so库问题解决方案2

        还有一种方法,将so库放到jniLibs文件夹中,如果没有此文件夹,需要手动创建,要注意与libs文件夹的目录位置是不同的。如用此方法不需要添加jniLibs.srcDirs = ['libs']

 

扫描二维码关注公众号,回复: 17380093 查看本文章

         之后再次执行,报错解决,但是有新的报错

(2)so库版本与当前设备架构不一致问题解决方案
System.err: java.lang.UnsatisfiedLinkError: dlopen failed: "/data/app/com.example.logdemo-2/lib/arm/libegalaxapijni.so" is 64-bit instead of 32-bit

        这个错误是由于架构不同导致的,该so库是64位架构的,但是我们运行的设备是32位的,其实我们的设备是armeabi-v7a的,我们设备不支持这个so库。解压缩对方的apk,找到lib目录

        从armeabi-v7a中拿到so库,重新拷贝到项目的libs下。之后再次执行,报错解决,但是有新的报错

(3)调用so库的类的包名与so库规定的包名不一致问题解决方案
System.err: java.lang.UnsatisfiedLinkError: JNI_ERR returned from JNI_OnLoad in "/data/app/com.example.logdemo-1/lib/arm/libegalaxapijni.so"

        出现该错误可能是调用so库的类的包名与so库规定的包名不一致导致的。

        我们知道,使用jni时,需要在一个.cpp文件下实现java与cpp的转换,该文件中的方法名一般是包名+类名+方法名,例如

Java_cn_com_chioy_vptprocesstool_utils_JniClient_doProcess(JNIEnv *env, jclass clazz,
                                                           jdoubleArray raw_data,jint data_length,
                                                           jobject vpt_result) {
   
   

        这个.cpp文件目前就已经打包成so库了,so库已经指明了包名+类名+方法名,所以用我自己新创建的工具类TouchScreenJNIUtil.getFWVersion()去调用是肯定不行的。

        查看反编译源码,找到对方调用jni的java类

        可以看到,包名为com.eeti.android.egalaxsensortester,类名为Native,方法名为 static native int getFWVersion(byte[] paramArrayOfbyte);

        所以在我们自己的项目下建立相同的包名,并且创建相同类名的java文件,其中的方法名也要保持一致,这里就不做展示了。

        至此,可以成功调用第三方so库中的getFWVersion()方法。后面还遇到了其他问题,但通过查看源码也解决了,在这里就不再讨论了。

猜你喜欢

转载自blog.csdn.net/khq1013/article/details/133678832