前言-現在市面主流的手機架構
- 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"文件等。有興趣的可以自行百度。