1. 程式人生 > >【走過巨坑】android studio對於jni呼叫及執行閃退無法載入庫的問題解決方案

【走過巨坑】android studio對於jni呼叫及執行閃退無法載入庫的問題解決方案

相信很多小夥伴都在android開發中遇到呼叫jni的各種巨坑,因為我們不得不在很多地方用到第三方庫so檔案,然而第三方官方通常都只會給出ADT環境下的整合方式,而谷歌親兒子android studio預設採用的卻是gradle方式,與ADT編輯的方式大不相同,那再andorid studio中如何匯入so檔案呢?

在android studio 中我們可能會用到jar包和so檔案的方式,對於jar包可能接觸更多,只需要我們把工程轉換為project顯示方式,開啟app下的libs資料夾,匯入即可。隨後再新增jar包為我們的工程依賴即可。

好吧,樓主不想跑題。對於so檔案也非常簡單,只需要在app/src/main下面建立一個jniLibs,再把我們的第三方so檔案拷貝進去即可,需要重點注意的是,我們安卓一般有幾種CPU,而不再是以前的只有armv5,目前有7種。ARMv5,ARMv7 (從2010年起),x86 (從2011年起),MIPS (從2012年起),ARMv8,MIPS64和x86_64 (從2014年起),每一種都關聯著一個相應的ABI。在Android系統上,每一個CPU架構對應一個ABI:armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64。而這些包的名字是不能隨便更改的。

而我們在開發中,應該儘可能的得到每一種ABI優化過的.so檔案,而不應該混合著使用,其實為每一種ABI提供對應的.so檔案其實也是SDK提供方應該做的,不過或許你不會這麼好運,也許你的SDK提供方就會像和樓主遇到的一樣,只給你提供一個armeabi方式的.so檔案,額,是的,你寫一個小demo測試SDK的功能可能是可用的,然後當你把你寫的demo引入到你的專案中後,你或許總能遇到這樣那樣的問題,比如,最常見的就是UnsatisfiedLinkError,當然你還可能遇到dlopen: failed以及其它各種形式的crash或者低下的效能。而你或許在有的手機上執行卻是不報任何錯誤的。比如樓主得到的第三方SDK,只提供了armeabi下的so檔案,樓主匯入到專案中後,(樓主專案之前支援了arm64-v8a等其他方式的ABI)使用相對版本老一點的手機執行,Ok,no problem!然而當用到小米系列的任何一款手機的時候,執行,直接Crash,原因在初始化的時候直接找不到某些.so檔案,導致無法使用System.loadLabray的方式載入,不知道遇上的小夥伴是怎麼解決的,不過就這麼一個問題,讓樓主和一些同樣的開發人員也是抓破了腦袋,樓主是知其原因,而不知其解決方案,這是最令人頭疼的。

下面是android studio的報錯資訊。

複製程式碼
08-21 11:12:48.413 7971-7971/com.hkyc.shouxinteacher.ischool E/AndroidRuntime: FATAL EXCEPTION: main
                                                                               Process: com.hkyc.shouxinteacher.ischool, PID: 7971
                                                                               java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file 
"/data/app/com.hkyc.shouxinteacher.ischool-2/base.apk"],nativeLibraryDirectories=[/data/app/com.hkyc.shouxinteacher.ischool-2/lib/arm64, /vendor/lib64, /system/lib64]]] couldn't find "libgnustl_shared.so" at java.lang.Runtime.loadLibrary(Runtime.java:366) at java.lang.System.loadLibrary(System.java:988) at com.idtechinfo.shouxiner.App.onCreate(App.java:92) at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1012) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4580) at android.app.ActivityThread.access$1500(ActivityThread.java:154) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1376) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5283) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
複製程式碼

好吧,真真令人頭疼,樓主採用了各種解決方式都沒有解決,因為android studio預設是會把所有ABI支援都打包到apk的,由於樓主得到的第三方SDK並不全面,所以遇上這樣的奇葩問題也是難免。

那麼,到底如何解決呢?

樓主通過網上提供的一些解決辦法說,可以在gradle中新增配置如下:

複製程式碼
 1 android {
 2     ... 
 3     splits {
 4         abi {
 5             enable true
 6             reset()
 7             include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for
 8             universalApk true //generate an additional APK that contains all the ABIs
 9         }
10     }
11 
12     // map for the version code
13     project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
14 
15     android.applicationVariants.all { variant ->
16         // assign different version code for each output
17         variant.outputs.each { output ->
18             output.versionCodeOverride =
19                     project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode
20         }
21     }
22  }
複製程式碼

可事實是:找不到包名!!到底什麼鬼?

樓主在各種碰壁後,希望大家不要再在這種低階問題上碰的頭破血流,樓主的解決方案是通過build.gradle設定讓apk打包只打包armeabi包下的.so檔案,

新增程式碼為:

複製程式碼
 1  
 2 
 3 android{
 4 
 5    .......
 6 
 7     defaultConfig {
 8         ndk {
 9             abiFilters 'armeabi','x86'
10         }
11     }
12 }
複製程式碼

當然,這樣雖然投機取巧在aremabi下的可以支援所有的CPU機型,但是無疑使用不到各種機型特定的效能優化,為了讓其不會閃退,樓主也只能暫時採用此類方法。如果大家有更好的方法,也希望能在評論區共享,謝謝。