日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
在安卓項(xiàng)目里部署so文件你需要知道的知識

1. 什么是CPU架構(gòu)及ABI

成都創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比鐘祥網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式鐘祥網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋鐘祥地區(qū)。費(fèi)用合理售后完善,10多年實(shí)體公司更值得信賴。

Android系統(tǒng)目前支持以下七種不同的CPU架構(gòu):ARMv***RMv7 (從2010年起),x86 (從2011年起),MIPS (從2012年起),ARMv8,MIPS64和x86_64 (從2014年起),每一種都關(guān)聯(lián)著一個(gè)相應(yīng)的ABI。

應(yīng)用程序二進(jìn)制接口(Application Binary Interface)定義了二進(jìn)制文件(尤其是.so文件)如何運(yùn)行在相應(yīng)的系統(tǒng)平臺上,從使用的指令集、內(nèi)存對齊到可用的系統(tǒng)函數(shù)庫。在Android系統(tǒng)上,每一個(gè)CPU架構(gòu)對應(yīng)一個(gè)ABI:armeabi,armeabi-v7a,x86,mips,arm64-v8a,mips64,x86_64。

2. 為什么需要重點(diǎn)關(guān)注.so文件

如果項(xiàng)目中使用到了NDK,它將會(huì)生成.so文件,因此顯然你已經(jīng)在關(guān)注它了。如果只是使用Java語言進(jìn)行編碼,你可能在想不需要關(guān)注.so文件了吧,因?yàn)镴ava是跨平臺的。但事實(shí)上,即使你在項(xiàng)目中只是使用Java語言,很多情況下,你可能并沒有意識到項(xiàng)目中依賴的函數(shù)庫或者引擎庫里面已經(jīng)嵌入了.so文件,并依賴于不同的ABI。例如,項(xiàng)目中使用RenderScript支持庫,OpenCV,Unity,android-gif-drawable,SQLCipher等,你都已經(jīng)在生成的APK文件中包含.so文件了,而你需要關(guān)注.so文件。

Android應(yīng)用支持的ABI取決于APK中位于lib/ABI目錄中的.so文件,其中ABI可能是上面說過的七種ABI中的一種。

Native Libs Monitor這個(gè)應(yīng)用可以幫助我們理解手機(jī)上安裝的APK用到了哪些.so文件,以及.so文件來源于哪些函數(shù)庫或者框架。當(dāng)然,我們也可以自己對APP反編譯來獲取這些信息,不過相對麻煩一些。

很多設(shè)備都支持多于一種的ABI,例如ARM64和x86設(shè)備也可以同時(shí)運(yùn)行armeabi-v7a和armeabi的二進(jìn)制包。但***是針對特定平臺提供相應(yīng)平臺的二進(jìn)制包,這種情況下運(yùn)行時(shí)就少了一個(gè)模擬層(例如x86設(shè)備上模擬arm的虛擬層),從而得到更好的性能(歸功于最近的架構(gòu)更新,例如硬件fpu,更多的寄存器,更好的向量化等)。我們可以通過Build.SUPPORTED_ABIS得到根據(jù)偏好排序的設(shè)備支持的ABI列表。但你不應(yīng)該從你的應(yīng)用程序中讀取它,因?yàn)锳ndroid包管理器安裝APK時(shí),會(huì)自動(dòng)選擇APK包中為對應(yīng)系統(tǒng)ABI預(yù)編譯好的.so文件,如果在對應(yīng)的lib/ABI目錄中存在.so文件的話。

3. .so文件應(yīng)該放在什么地方

我們往往很容易對.so文件應(yīng)該放在或者生成到哪里感到困惑,下面是一個(gè)總結(jié):

  • Android Studio工程放在main/jniLibs/ABI目錄中(當(dāng)然也可以通過在build.gradle文件中的設(shè)置jniLibs.srcDir屬性自己指定)
  • Eclipse工程放在libs/ABI目錄中(這也是ndk-build命令默認(rèn)生成.so文件的目錄)
  • AAR壓縮包中位于jni/ABI目錄中(.so文件會(huì)自動(dòng)包含到引用AAR壓縮包的APK中)
  • 最終APK文件中的lib/ABI目錄中
  • 通過PackageManager安裝后,在小于Android 5.0的系統(tǒng)中,.so文件位于app的nativeLibraryPath目錄中;在大于等于Android 5.0的系統(tǒng)中,.so文件位于app的nativeLibraryRootDir/CPU_ARCH目錄中。

4. 安裝Apk時(shí)PackageManagerService選擇解壓so文件的策略

在Android系統(tǒng)中,當(dāng)我們安裝Apk文件的時(shí)候,lib目錄下的so文件會(huì)被解壓App的原生庫目錄,一般來說是放到/data/data/package-name/lib目錄下,而根據(jù)系統(tǒng)和CPU架構(gòu)的不同,其拷貝策略也是不一樣的,不正確地配置so文件,比如某些App使用第三方的so時(shí),只配置了其中某一種CPU架構(gòu)的so,可能會(huì)造成App在某些機(jī)型上的適配問題。

Android版本

so拷貝策略

策略問題

5. 配置so的建議

針對Android 系統(tǒng)的這些拷貝策略的問題,我們給出了一些配置so的建議:

5.1 針對armeabi和armeabi-v7a兩種ABI

  • 方法1:由于armeabi-v7a指令集兼容armeabi指令集,所以如果損失一些應(yīng)用的性能是可以接受的,同時(shí)不希望保留庫的兩份拷貝,可以移除armeabi-v7a目錄和其下的庫文件,只保留armeabi目錄;比如Apk使用第三方的so只有armeabi這一種ABI時(shí),可以考慮去掉Apk中l(wèi)ib目錄下armeabi-v7a目錄。
  • 方法2:在armeabi和armeabi-v7a目錄下各放入一份so。

5.2 針對x86

目前市面上的x86機(jī)型,為了兼容arm指令,基本都內(nèi)置libhoudini模塊,即二進(jìn)制轉(zhuǎn)碼支持,該模塊負(fù)責(zé)把ARM指令轉(zhuǎn)換為x86指令,所以如果是出于Apk包大小的考慮,并且可以接受一些性能損失,可以選擇刪掉x86庫目錄,x86下配置的armeabi目錄的so庫一樣可以正常加載使用。

5.3 針對64位ABI

如果App開發(fā)者打算支持64位,那么64位的so要放全,否則可以選擇不單獨(dú)編譯64位的so,全部使用32位的so,64位機(jī)型默認(rèn)支持32位so的加載。比如Apk使用第三方的so只有32位ABI的so,可以考慮去掉Apk中l(wèi)ib目錄下的64位ABI子目錄,保證Apk安裝后正常使用。

5. Android Studio配置abiFilters

 
 
 
 
  1. android {  
  2. defaultConfig {  
  3. ndk {  
  4. abiFilters 'armeabi-v7a' //, 'armeabi', 'arm64-v8a', 'x86', 'x86_64', 'mips', 'mips64'  
  5. }  
  6. }  

這句話的意思就是指定NDK需要兼容的架構(gòu),把除了armeabi-v7a以外的兼容包都過濾掉,只剩下一個(gè)armeabi-v7a的文件夾。

即使我們沒有指定其他的兼容框架,也需要一個(gè)過濾。當(dāng)我們接入多個(gè)第三方庫時(shí),很可能第三方庫做了多個(gè)平臺的兼容。譬如fresco就做了各個(gè)平臺的兼容,所以它創(chuàng)建了各個(gè)兼容平臺的目錄。因?yàn)橹灰霈F(xiàn)了這個(gè)目錄,系統(tǒng)就只會(huì)在這個(gè)目錄里找.so文件而不會(huì)遍歷其他的目錄,所以就出現(xiàn)了找不到.so文件的情況。

6. java.lang.UnsatisfiedLinkError

該錯(cuò)誤類型較多,以下進(jìn)行分類:

 
 
 
 
  1. java.lang.UnsatisfiedLinkError : dlopen failed: library //dlopen打開失敗  
  2. java.lang.UnsatisfiedLinkError :findLibrary returned null //找不到library  
  3. java.lang.UnsatisfiedLinkError : Native method not found //找不到對應(yīng)函數(shù) 
  4.  java.lang.UnsatisfiedLinkError :Cannot load library: load_library //無法load library 

出現(xiàn)原因:

顯然出現(xiàn)上述崩潰的根本原因是:

  • (1)so無法加載,可能是so不存在等原因
  • (2)so正常加載,但是沒有找到相應(yīng)的函數(shù)

針對第二個(gè)原因,顯然相對來說很容易排查,而且在開發(fā)中,這樣的函數(shù)調(diào)用必然會(huì)在編譯時(shí)和debug模式下進(jìn)行測試,所以這種原因產(chǎn)生的概率很小。

那么下面主要總結(jié)幾類“so無法加載”而導(dǎo)致上述崩潰的幾種原因:

6.1 生成的so本身缺陷

一個(gè)簡單的例子:

crash堆棧:

 
 
 
 
  1. java.lang.UnsatisfiedLinkError: Cannot load library: find_library(linker.cpp:889): "/data/data/com.netease.nis.apptestunit/app_lib/libdemo.so" failed to load previously 
  2. at java.lang.Runtime.load(Runtime.java:340)  
  3. at java.lang.System.load(System.java:521)  
  4. at com.netease.nis.bugrpt.ReLinker.loadLibrary(ReLinker.java:76)  
  5. at com.example.crash.MainActivity.onCreate(MainActivity.java:272)  
  6. at android.app.Activity.performCreate(Activity.java:5220)  
  7. at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1086)  
  8. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2193)  
  9. at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2279)  
  10. at android.app.ActivityThread.access$600(ActivityThread.java:142)  
  11. at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1272)  
  12. at android.os.Handler.dispatchMessage(Handler.java:99)  
  13. at android.os.Looper.loop(Looper.java:137)  
  14. at android.app.ActivityThread.main(ActivityThread.java:5105)  
  15. at java.lang.reflect.Method.invokeNative(Native Method)  
  16. at java.lang.reflect.Method.invoke(Method.java:511)  
  17. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)  
  18. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)  
  19. at dalvik.system.NativeStart.main(Native Method) 

解決方法:

查看原項(xiàng)目Application.mk,發(fā)現(xiàn)APP_STL := gnustl_shared。原方案使用的是共享庫,這不一定都支持所有的機(jī)型,改用靜態(tài)庫gnustl_static問題解決。

對應(yīng)的在Android Studio中需要將共享庫改用靜態(tài)庫gnustl_static。這一類關(guān)于so編譯共享庫問題,需要進(jìn)行檢查。

 
 
 
 
  1. APP_STL 可用值  
  2. system 系統(tǒng)默認(rèn)  
  3. stlport_static - 使用STLport作為靜態(tài)庫  
  4. stlport_shared - 使用STLport 作為共享庫  
  5. gnustl_static - 使用GNU libstdc++ 作為靜態(tài)庫  
  6. gnustl_shared - 使用GNU libstdc++ 作為共享庫 

上述例子只是一個(gè)簡單的例子,可能在so編譯生成時(shí),由于沒有考慮共享庫的機(jī)型匹配等原因?qū)е耈nsatisfiedLinkError崩潰,其次是64位32位系統(tǒng)架構(gòu)問題,也可能導(dǎo)致UnsatisfiedLinkError崩潰。

6.2 手機(jī)設(shè)備沒有空間

在so正確生成情況下,會(huì)根據(jù)設(shè)置的支持so庫框架生成對應(yīng)的庫。在Android系統(tǒng)中,當(dāng)我們安裝Apk文件的時(shí)候,lib目錄下的so文件會(huì)被解壓到App的原生庫目錄,一般來說是放到/data/data/package-name/lib目錄下,當(dāng)準(zhǔn)備加載native層的so時(shí),雖然在Apk中有對應(yīng)的so文件,但是由于手機(jī)設(shè)備沒有足夠的空間加載該so,導(dǎo)致加載失敗,產(chǎn)生上述崩潰。

6.3 so配置錯(cuò)誤

倘若so正確生成,且手機(jī)空間充足,那么如上所述,在Android系統(tǒng)中,當(dāng)我們安裝Apk文件的時(shí)候,lib目錄下的so文件會(huì)被解壓到App的原生庫目錄,一般來說是放到/data/data/package-name/lib目錄下。但是根據(jù)系統(tǒng)和CPU架構(gòu)的不同,其拷貝策略也是不一樣的。倘若不正確地配置了so文件,比如某些App使用第三方的so時(shí),只配置了其中某一種CPU架構(gòu)的so,可能會(huì)造成App在某些機(jī)型上的適配問題,產(chǎn)生上述崩潰。

6.4 Android的PackageManager安裝問題

用戶安裝了與手機(jī)CPU架構(gòu)不符的Apk安裝包,或者App升級過程中因各種原因未正確釋放so文件。這種問題可以使用ReLinker解決。

使用ReLinker十分簡單,使用

 
 
 
 
  1. ReLinker.loadLibrary(context, “mylibrary”) 

代替標(biāo)準(zhǔn)的即可。

 
 
 
 
  1. System.loadLibrary(“mylibrary”); 

文章名稱:在安卓項(xiàng)目里部署so文件你需要知道的知識
文章源于:http://m.5511xx.com/article/coscsii.html