使用第三方庫出現找不到so庫UnsatisfiedLinkError錯誤的原因以及解決方案
字數1563 閱讀913 評論2 喜歡2
在開發項目的時候我們免不了使用一些第三方的庫來進行快速開發,有些第三方庫只是簡單的一個jar包,但是有些使用了jni開發,因此會包含so庫文件,這個時候如果不消息我們就會遇到一個錯誤:java.lang.UnsatisfiedLinkError;
最近經常遇到有開發者在問使用環信sdk的時候出現這個錯誤;這里分享下問題原因以及解決方案;
首先這邊引用環信工程師總結的出現這個問題的一些原因(稍作排版修改):
導致產生UnsatisfiedLinkError的幾個原因
原文地址:UnsatisfiedLinkError錯誤分析
相關信息
hyphenatechatsdk提供的指令集類型僅提供armeabi、arm64-v8a、x86三種;
這里需要解釋一下相關信息:
armeabi和armeabi-v7a是相近似的指令集,v7a是增強型指令集,運行速度,效率均有所提高,他們都是32位指令,並且兼容;arm64-v8a對應arm64位指令集;
arm64位策略和intel IA32不一樣:intel64位指令是兼容intel32位指令,intel32位指令編譯的程序可以直接在intel64位機器上運行;但是arm不是,arm64位和arm32位是彼此獨立的指令系統,不兼容;arm這樣設計的原因是因為運行在嵌入式上,設計指標更趨向於效率,和耗電考量;實際上arm64位芯片上同時包含着arm64指令處理器和arm32位指令處理器,只不過兩個處理器彼此獨立;
影響鏈接的限制條件
armeabi的so實際上可以運行在arm64位機器上,只不過Google增加了限制條件:
Android4.x只要能找到so,就可以運行,so可以在armeabi、armeabi-v7a、arm64-v8a,so位置可以很隨意;
Android5.x開始,檢查更加嚴格,會只有和芯片型號對應目錄的so會安裝到手機中;
舉個例子:
開發環境下目錄結構如下
libs/armeabi:libhyphenate.so libhyphenate_av.so
libs/armeabi-v7a:libmediadata.so
手機對應的指令集是armeabi-v7a,然后安裝到手機的只有libmediadata.so;
Android6.x下,檢查更加嚴格,有一條規則,之前測試有遇到,現在不太確認;
libs/armeabi/: libhyphenate.so libhyphenate_av.so
libs/arm64-v8a(沒有此目錄)
在arm64位機器上也可以運行,但是作為開發者通常會依賴其他開發包,比如baiduMap,也會用其他so,不能讓所有開發者都刪掉libs/arm64-v8a的目錄;不過開發者可以嘗試下刪除arm64-v8a,只留armeabi,這樣安裝包會很小,在各個平台上也能運行;
Google考量點是執行速率,更流暢的用戶體驗,作為開發者,服務提供者,我們希望apk盡可能小,對執行速度要求不高;
armeabi和armeabi-v7a可以互換,現在市面上的手機很少有armeabi的,基本上是armeabi-v7a或arm64位的高端機器。
查看手機芯片型號:cat /proc/cpuinfo, 仔細看一下打印信息,能夠看明白手機指令集,是32位還是64位。
x86目錄,通常對應虛擬機,很多開發者喜歡在genymotion上開發調試,這個就對應86,x86和前面說的intel IA32是一回事,所以只提供32位的,也能在x86-64位機器上運行;
我們的so還依賴於libsqlite.so,不過由於這個包從來沒有變化,使用的是系統默認提供的/system/lib,在Android 6.x及以下的平台可以運行,Android7.x執行更嚴格的安全檢查,禁止使用系統目錄的內容,所以如果希望在Android7.x以上版本,需要把系統目錄的libsqlite.so拷貝出來,也放在自己app對應指令目錄下,由於目前Android7.x市面上沒有機型,所以目前不在考慮范圍;
mips指令集的手機很少見,聽說聯想有出過,沒見過;
libs/armeabi/libhyphenate.so和libs.without.audio/armeabi/libhyphenate.so是不同,libs/armeabi/libhyphenate.so會依賴於libs/armeabi/libhyphenate_av.so,如果找不到會報java.lang.UnsatisfiedLinkError;
還有一個比較容易忽略的一點,現在我們的的項目一般都是引入好多個第三方庫,第六點也提到了使用baiduMap這點,就是當一個項目引入多個庫,不同的庫有不同的so文件夾,當其中一個支持的比較少,但是另一個比較全時,也會出現這樣的錯誤,解決方法就是不支持的so文件夾刪除
舉例:
環信支持的指令集arm64-v8a、armeabi、x86
百度地圖支持的指令集arm64-v8a、armeabi、armeabi-v7a、x86、x86_64、mips、mips64
如果想在所有設備上都能運行,需要把armeabi-v7a、x86_64、mips、mips64這些刪除;
根據前邊所說可以保留armeabi-v7a文件夾,然后復制armeabi里的so文件到armeabi-v7a就行了
所以如果大家再遇到這樣的問題,可以先根據以上信息排查下,如有問題歡迎指正
那么問題來了,到底是什么原因呢?
通過分析crash日志,我發現一個問題:
nativeLibraryDirectories=[/data/app/xxx-1/lib/arm64, /data/app/xxx-1/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]
我外部的lib里並沒有那么多文件夾啊!!!!
這個就是crash的原因所在了。
當AAR內部的so文件類型比外部多時,會導致外部的so文件找不到。
所以果斷的剔除了AAR中不需要的so文件夾“arm64”,“arm64-v8a”,“x86”。
再次編譯,OK,齊活了。88,希望能幫助到你們。
文/13itch(簡書作者)
原文鏈接:http://www.jianshu.com/p/7e37b76ae39a
著作權歸作者所有,轉載請聯系作者獲得授權,並標注“簡書作者”。
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile(name: 'mylib', ext: 'aar')
}
注意:在defaultConfig中不要定義applicationId,因為aar是庫,無applicationId
2.如何在工程中導入aar?
(1)將編譯好的aar文件放到libs下,類似jar的做法。譬如,libs/mylib.aar。
(2)在工程的build.gradle中添加:
在CODE上查看代碼片派生到我的代碼片
repositories{
flatDir {
dirs 'libs'
}
}