【走過巨坑】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'
10         }
11     }
12 }

 

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

 轉載請在醒目位置附上本文鏈接:http://www.cnblogs.com/liushilin/p/5792505.html

 

 

2017-03-06補充

如果你作這樣的更改后依然不行的話,可能是你的.so文件采用了較低版本的SDK編譯,此時通常可以將targetSdkVersion設置為22就可以解決了,如果還是不能解決,可以嘗試繼續降低targetSdkVersion的版本。

另外,樓主在后面專門更新了.so文件庫的解讀,可以去看看:【開發必備】今天我們來談談Android NDK動態鏈接庫(so文件)的一些見解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM