背景
最近公司设备换了新的触摸屏(为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']
之后再次执行,报错解决,但是有新的报错
(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文件,其中的方法名也要保持一致,这里就不做展示了。
文章来源:https://www.toymoban.com/news/detail-859187.html
至此,可以成功调用第三方so库中的getFWVersion()方法。后面还遇到了其他问题,但通过查看源码也解决了,在这里就不再讨论了。文章来源地址https://www.toymoban.com/news/detail-859187.html
到了这里,关于AndroidStudio调用第三方so库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!