前言-现在市面主流的手机架构
- x86/x86_64:这种架构手机包含由Intel提供的指令集转码工具,实现了对arm的兼容,使用这种架构的手机市场占有率很低。
- mips/mips64:极少手机使用这种架构,有兴趣可以自行百度。
- armeabi ARM v5:相当老旧的版本,缺少对浮点数计算的硬件支持,需要大量计算时有性能瓶颈。
- armeabi-v7a ARM v7:现在市面上主流版本,比如骁龙、麒麟处理器等大部分处理器采用这种架构。
- arm64-v8a ARM v8 :64位的
问题1 cannot find “libxxx.so”
原因分析
一. 存放路径不对,默认是放在src/jniLibs,而手动指定目录后放错了位置。
Android Studio一般把so文件放在jnilibs目录下对应的框架名文件夹下(比如:armeabi、armeabi-v7a、arm64-v8a)。你也可以自己定义jni的目录。
如下在工程级别的gradle下设置了路径myJniLibs,那文件就要放到这个目录下对应架构文件里。
sourceSets.main {
jniLibs.srcDirs = ['src/main/myJniLibs']
}
二. 由于不同框架下的so文件名称不同,造成的找不到。
一般情况下,一组so文件名称都是一样的,放在不同的架构文件夹下。使用的时候直接通过一行代码就能加载。
//放到库文件的so文件→libxxx.so
System.loadLibrary("xxx");
但是对于情况2则要手动判断cpu架构,以ffmpeg的so文件为例,代码如下
try {
//判断cpu架构,拿到不同的so文件
if (Build.class.getField("CPU_ABI").get(null).toString().startsWith("arm64-v8a")) {
System.loadLibrary("ffmpeg-squirrel-arm64-v8a");
} else {
System.loadLibrary("ffmpeg-squirrel-armeabi-v7a");
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
三. 32位系统的手机不会报错,64位系统的手机报错
“xxx.so” is 32-bit instead of 64-bit
分析:项目中使用了多个第三方的sdk。有的sdk提供了32位和64位的so文件,有的sdk只提供了32位的so文件。当使用64位手机去拿某个只提供了32位so文件sdk的库文件的时候,由于只会去64位架构文件下找,但是找不到(64位的文件夹存在,但是里面没有我要的这个so文件)。
解决办法:
- 把64位的文件夹全删了,因为向下兼容,就回去32位文件下找。
- 自己编译64位的so,或者叫第三方提供。(一般源码找不到,就只能找第三方弄)
问题2 java.lang.UnsatisfiedLinkError: JNI_ERR returned from JNI_OnLoad
加载so文件的代码所在的类,需要和so文件实现所在的类是同一个包名,不然它找不到so文件中native方法的实现。
出错原因:打so包的那个ndk-build的配置文件的packageName和加载so文件那个类的包名不一致。
后话-打出一个so文件
不管是Eclipse还是AndroidStudio,只要配置了ndk的环境变量(Linux系统忽略,Windows在系统变量的Path里添加你的ndk-bundle文件目录),就可以打出so。
- 打开命令行。切到jni所在目录。
- Android.mk和Application.mk2个文件配置一下。
- 命令行输入ndk-build命令。
例子
1、Application.mk
//打出所有类型的so,也可以写几个你需要的 APP_ABI := armeabi,armeabi-v7a,arm64-v8a
APP_ABI := all
2、Android.mk
这个文件比较复杂,就不贴了。大概就是定义路径的变量,so包名称,本地src路径下的一些".c"文件等。有兴趣的可以自行百度。