Android中so使用知識和問題總結以及外掛開發過程中載入so的方案解析
一、前言
Android中有時候為了效率以及平臺開發庫的支援,難免會用到NDK開發,那麼都會產生一個so檔案,通過native方法進行呼叫,開發和呼叫步驟很簡單,這裡就不多說了,本文主要來介紹,我們在使用so的時候總是會出現一些常見的問題,而現在外掛化開發也很普遍了,有時候外掛中也會包含一些so檔案,需要載入,這時候也會出現一些問題。本文就來詳細總結一下這些問題出現的原因,以及解決方法,主要還是通過原始碼來分析。
二、涉及到的原始碼類
因為本文主要通過分析原始碼來分析so使用的知識點和問題總結,所以涉及到了很多的原始碼類,這裡就現提供一下:
1、PackageManagerService.java
+setNativeLibraryPaths:設定應用的native庫路徑
+scanPackageDirtyLI:掃描包內容初始化應用資訊
2、ActivityManagerService.java
+startProcessLocked:傳送命令給Zygote程序啟動一個虛擬機器
3、NativeLibraryHelper.java
底層實現類:com_android_internal_content_NativeLibraryHelper.cpp
+copyNativeBinariesWithOverride:釋放apk中的so檔案到本地目錄
+findSupportedAbi:遍歷apk中的so檔案結合abiList值得到應用支援的abi型別索引值
4、LoadApk類和ApplicationLoaders類
5、VMRuntime.java
底層實現類:dalvik_system_VMRuntime.c
+getInstructionSet:獲取虛擬機器的指令集型別
+is64BitAbi:判斷VM是否為64位
6、Runtime.java
底層實現類:dalvik/vm/native/java_lang_Runtime.cpp,dalvik/vm/Native.cpp
+nativeLoad:載入so檔案
三、Android中so檔案的編譯平臺
Android中在進行NDK開發的時候,都知道因為機型雜而多的原因,沒有一個大的標準,所以很多廠商都會採用不同型號的cpu,那麼在編譯so檔案的時候,就需要進行交叉編譯出多個cpu平臺版本,現在主流的cpu架構版本:
armeabi/armeabi-v7a:這個架構是arm型別的,主要用於Android4.0之後的,cpu值32位的
x86/x86_64:這個架構是x86型別的,有32位和64位,佔用的裝置比例比較小
arm64-v8:這個架構是arm型別,主要用於Android5.0之後,cpu是64位的
這裡可以看到,其中arm型別的是往下相容策略,比如arm64-v8a肯定相容armeabi/armeabi-v7a,也就是說armeabi/armeabi-v7a架構的so檔案可以用在arm64-v8a的裝置中的,而armeabi-v7a也是相容armeabi的,但是因為cpu型號不同,所以arm體系和x86體系之間是不能相互相容的。
四、Android中so載入流程
在Android中如果想使用so的話,首先得先載入,載入現在主要有兩種方法,一種是直接System.loadLibrary方法載入工程中的libs目錄下的預設so檔案,這裡的載入檔名是xxx,而整個so的檔名為:libxxx.so。還有一種是載入指定目錄下的so檔案,使用System.load方法,這裡需要載入的檔名是全路徑,比如:xxx/xxx/libxxx.so。
上面的兩種載入方式,在大部分場景中用到的都是第一種方式,而第二種方式用的比較多的就是在外掛中載入so檔案了。
不管是第一種方式還是第二種方式,其實到最後都是呼叫了Runtime.java類的載入方法doLoad:
這裡會先從類載入中獲取到nativeLib路徑,然後在呼叫native方法nativeLoad(java_lang_Runtime.cpp):
這裡呼叫了一個核心的方法dvmLoadNativeCode(dalvik/vm/Native.cpp):
注意:
這裡有一個檢測異常的程式碼,而這個錯誤,是我們在使用外掛開發載入so的時候可能會遇到的錯誤,比如現在我們使用DexClassLoader類去載入外掛,但是因為我們為了外掛能夠實時更新,所以每次都會賦值新的DexClassLoader物件,但是第一次載入so檔案到記憶體中了,這時候退出程式,但是沒有真正意義上的退出,只是關閉了Activity了,這時候再次啟動又會賦值新的載入器物件,那麼原先so已經載入到記憶體中了,但是這時候是新的類載入器那麼就報錯了,解決辦法其實很簡單,主要有兩種方式:
第一種方式:在退出程式的時候採用真正意義上的退出,比如呼叫System.exit(0)方法,這時候程序被殺了,載入到記憶體的so也就被釋放了,那麼下次賦值新的類載入就在此載入so到記憶體了,
第二種方式:就是全域性定義一個static型別的類載入DexClassLoader也是可以的,因為static型別是儲存在當前程序中,如果程序沒有被殺就一直存在這個物件,下次進入程式的時候判斷當前類載入器是否為null,如果不為null就不要賦值了,但是這個方法有一個弊端就是類載入器沒有從新賦值,如果外掛這時候更新了,但是還是使用之前的載入器,那麼新外掛將不會進行載入。
繼續往下看:
這裡主要呼叫了兩個核心的系統方法,dlopen和dlsym,這兩個方法用途還是很多的,一般是先載入so檔案,然後得到指定函式的指標,最後直接呼叫即可,主要用於呼叫動態的呼叫so中的指定函式功能。而且這裡注意到了最開始先呼叫so中的JNI_OnLoad函式,這個函式是so被載入之後呼叫的第一個方法。
到這裡我們就總結一下Android中載入so的流程:
1、呼叫System.loadLibrary和System.load方法進行載入so檔案
2、通過Runtime.java類的nativeLoad方法進行最終呼叫,這裡需要通過類載入器獲取到nativeLib路徑。
3、到底層之後,就開始使用dlopen方法載入so檔案,然後使用dlsym方法呼叫JNI_OnLoad方法,最終開始了so的執行。
五、Android中類載入器關聯so路徑
上面分析so載入過程中可以發現有一個地方,就是通過類載入器來獲取到so的路徑,那麼Android中的主要類載入器有兩個,一個是PathClassLoader和DexClassLoader,關於這兩個類載入不多說了,網上資料很多可以自行查詢閱讀。而PathClassLoader是我們Android中預設的類載入器,也就是apk檔案就是由他來載入的,我們可以通過檢視原始碼得知,Android中載入apk的類載入可以從LoadApk.java類查詢到:
注意:
這個類很重要的,而這個類載入器也是我們在做外掛的時候,需要做一些操作,比如需要把載入外掛的DexClassLoader類給新增到這個系統載入器中,就可以解決外掛中元件的生命週期問題。
看看這個類載入器在哪裡賦值的:
去看看ApplicationLoaders.java類:
看到了,這裡就是定義了PathClassLoader類了,所以我們Android中應用的預設載入器是PathClassLoader,再去看看這個類載入器的nativeLib是哪裡:
六、Android中so檔案如何釋放
我們在使用System.loadLibrary載入so的時候,傳遞的是so檔案的libxxx.so中的xxx部分,那麼系統是如何找到這個so檔案然後進行載入的呢?這個就要先從apk檔案安裝時機說起。
我們如果還沒有分析原始碼之前,大致能夠猜想到的流程是:
在安裝apk的時候,系統解析apk檔案,因為so檔案肯定是存放在libs下指定平臺目錄中的,而apk檔案本身就是一個壓縮檔案,所以可以進行解壓,然後讀取libs目錄下的so檔案,進行本地釋放解壓到指定目錄,然後在載入的時候就先拼接so檔案的全路徑,最後在進行載入工作即可。
通過猜想,下面就通過原始碼來分析一下流程,系統在安裝apk的時候,是呼叫系統類:PackageManagerService.java類:
主要的核心方法是scanPackageDirtyLI:
這個方法主要通過傳遞的pkg變數,開始構造applicationInfo資訊。我們往下面看,找到設定nativeLib資訊的程式碼:
這裡注意有一個判斷,是不是多平臺架構的應用:
所以,我們看看info.flags有沒有設定這個標誌,我們看到上面的pkg變數是通過解析apk檔案的類PackageParser.java類中獲取到的,所以可以去這個類中找這個標誌位的設定。
這裡看到了,如果在AndroidManifest.xml中設定了Application中的multiArch屬性值的話就有,但是我們預設都沒有設定這個屬性值,那麼就是false,也就是說一般應用都不是多平臺的。所以上面的isMultiArch方法就返回false,程式碼就走到了這裡:
在這裡就有很多知識點了,而這裡可以看到,就涉及到了so檔案的釋放工作了,主要是在NativeLibraryHelper類中,但是這裡看到首先獲取abiList值:
通過Build.SUPPORTED_ABIS來獲取到的:
最終是通過獲取系統屬性:ro.product.cpu.abilist的值來得到的,我們可以使用getprop命令來檢視這個屬性值:
這裡獲取到的值是:arm64-v8a,armeabi-v7a,armeabi,我用的是64位的cpu裝置,所以可以看到他有多個cpu架構可選,而且看到這個順序會想到,這個順序正好是向下相容的順序。
現在去看看NativeLibraryHelper類的copyNativeBinariesForSupportedAbi方法:
這個方法中主要乾了三件事:
第一件事是獲取應用所支援的arch架構型別
第二件事是通過架構型別獲取so釋放的目錄
第三件事是native層中釋放apk中的指定架構的so到裝置目錄中
第一件事:獲取應用所支援的arch架構型別
NativeLibraryHelper類的findSupportedAbi方法,其實這個方法就是查詢系統當前支援的架構型號索引值:
看看native方法的實現:
這裡看到了,會先讀取apk檔案,然後遍歷apk檔案中的so檔案,得到全路徑然後在和傳遞進來的abiList進行比較,得到合適的索引值,其實實現邏輯很簡單:abiList是:arm64-v8a,armeabi-v7a,armeabi,然後就開始比例apk中有沒有這些架構平臺的so檔案,如果有,就直接返回abiList中的索引值即可,比如說apk中的libs結構如下:
那麼這時候返回來的索引值就是0,代表的是arm64-v8a架構的。如果apk檔案中沒有arm64-v8a目錄的話,那麼就返回1,代表的是armeabi-v7a架構的。依次類推。得到應用支援的架構索引之後就可以獲取so釋放到裝置中的目錄了。
第二件事:獲取so釋放之後的目錄
這裡主要通過VMRuntime.java中的getInstructionSet方法:
這裡呼叫了一個map結構值:
這裡的arch架構和目錄對應關係,如果arch是arm64-v8a的話,那麼目錄就是arm64了。
第三件事:釋放apk中的so檔案
直接呼叫的是native層方法iterateOverNativeFiles:
好了到這裡就講完了上面的三件事了,而這三件事做完之後,apk中的so檔案就會被釋放到本地裝置中的指定目錄中了,當然這裡系統會根據abiList中的值以及apk中包含的arch型別的so來決定釋放哪個目錄中的so檔案,比如這裡通過ApplicationInfo類來列印當前應用的nativeLibraryDir值:
列印的結果:
看到了,因為是arm64-v8a型別的,所以目錄是arm64的,而且可以看到這個應用不是多平臺的。
我們可以看到Android中是如何釋放apk中的so檔案到本地目錄的:
1、通過遍歷apk檔案中的so檔案的全路徑,然後和系統的abiList中的型別值進行比較,如果匹配到了就返回arch型別的索引值
2、得到了應用所支援的arch型別之後,就開始獲取建立本地釋放so的目錄
3、然後開始釋放so檔案
我們在PackageMangerService類中繼續往下看:
這裡還要儲存上面獲取到應用支援的arch型別值,我們可以使用反射列印這個值:
列印結果:
這個值在後面應用建立VM的時候會用到。
接著開始設定應用的nativeLib路徑了:
看看這個方法的實現:
這裡先判斷是不是64位:
通過arch型別對應的目錄來判斷的:
這裡如果是64位,目錄就是lib,如果是32位就是lib64:
這樣就和我們上面釋放so檔案的目錄保持一致了,所以這裡的ApplicationInfo類中的lib路徑就是我們上面釋放so之後的路徑了。
在之前說到了類載入器中的lib路徑,我們可以列印一下庫路徑的,這裡直接使用getClassLoader得到載入器列印即可:
這裡看到Library的目錄包含很多路徑。
七、Android中64位系統如何相容32位的so
上面分析完了,so檔案的釋放工作,下面繼續來看一下如果一個64位系統的Android裝置如何做到能夠執行32位的so檔案,這個就需要從應用的啟動說起了,那麼這個類就是ActivityManagerService.java,有一個核心的方法:startProcessLocked,這個方法就是向Zygote程序傳送一個訊息,為這個應用建立虛擬機器開始執行程式了:
這裡在傳送訊息給Zygote程序,看到這裡通過ApplicationInfo中的primaryCpuAbi型別告訴Zygote改建立多少位的虛擬機器,我們檢視系統啟動檔案init.rc內容:
這裡會啟動一個64位的Zygote程序
然後啟動一個32位的Zygot程序
所以這裡應該就可以想明白了,原來系統啟動的時候,如果是64位的系統裝置,會啟動兩個Zygote程序用來相容32位型別的應用,我們可以使用ps命令檢視程序:
看到了,這裡果然啟動了兩個Zygote程序,一個64位的,一個是32位的。所以相容功能的大致流程圖應該是這樣的:
上層啟動應用的時候會把應用的abi型別帶過來,然後這裡會根據這個型別傳送給具體的Zygote程序訊息,來建立虛擬機器開始執行程式,這樣就做到了相容。
八、Android外掛中如何載入so檔案
有時候我們在開發外掛的時候,可能會呼叫so檔案,一般來說有兩種方案:
一種是在載入外掛的時候,先把外掛中的so檔案釋放到本地目錄,然後在把目錄設定到DexClassLoader類載入器的nativeLib中。
一種在外掛初始化的時候,釋放外掛中的so檔案到本地目錄,然後使用System.load方法去全路徑載入so檔案
這兩種方式的區別在於,第一種方式的程式碼邏輯放在了宿主工程中,同時so檔案可以放在外掛的任意目錄中,然後在解壓外掛檔案找到這個so檔案釋放即可。第二種方式的程式碼邏輯是放在了外掛中,同時so檔案只能放在外掛的assets目錄中,然後通過把外掛檔案設定到程式的AssetManager中,最後通過訪問assets中的so檔案進行釋放。
上面就全部分析完了Android中關於so載入的相關內容:
1、so編譯平臺問題
2、so載入流程分析
3、so檔案釋放功能分析
4、so檔案相容功能分析
5、外掛中so檔案呼叫功能分析
九、常見問題分析
第一個問題:Could not find libxxx.so
這個問題看上去很好理解,就是在呼叫載入so的方法的時候,到底層使用dlopen方法開啟so檔案,發現找不到這個so檔案,那麼這個問題產生的原因主要有兩個:
第一個是我們的確忘了在工程的libs下存放so檔案了;
第二個是我們把so檔案放錯目錄了;
第一個原因就不多說了,主要來看第二原因:
有時候我們在開發專案的時候,可能會放多個架構型別的so檔案,那麼現在假如我的裝置是arm64-v8a型別的,我的專案中有三個so檔案,比如叫做AAA.so,BBB.so,CCC.so,然後我再arm64-v8a目錄中放了AAA.so,BBB.so,而CCC.so忘了放了,但是會放到armeabi-v7a和armeabi目錄中,那麼這時候就會發生找不到CCC.so的錯誤,原因很簡單:
上面分析了apk中so檔案的釋放邏輯,系統會先遍歷apk中所有so檔案的全路徑,然後在結合abiList的值來決定最終釋放哪個目錄中的so檔案,那麼現在系統是arm64-v8a了,而apk中的libs下也有arm64-v8a,所以這裡就會把apk中的libs\arm64-v8a中的所有so檔案釋放解壓到本地目錄中,而不會在去釋放armeabi/armeabi-v7a了。因為arm64-v8a中沒有CCC.so檔案,所以最終釋放到本地目錄中也是沒有這個so檔案的,所以載入時找不到檔案了。
解決辦法:就是在使用so檔案的時候,需要確定在每個架構型別目錄中都要有相同的so檔案即可。
第二個問題:32-bit instead of 64-bit
這個問題的原因主要是因為64位的Zygote程序建立的虛擬機器中載入了32位的so檔案,這個問題的產生原因主要有兩個:
第一個是我們把不同架構型別的so檔案放錯目錄了,比如armeabi/armeabi-v7a的so檔案放到了arm64-v8a中了
第二個是我們在開發外掛的過程中,宿主工程中有arm64-v8a目錄,但是外掛中載入so卻是armeabi/armeabi-v7a型別的
第一個原因就不多說了,主要是因為so放錯目錄了,來看一下第二個原因,我們在開發外掛的時候有時候需要在外掛中去載入so檔案,一般都是使用System.load方式去載入全路徑的so檔案,那麼這裡就可能存在一個問題,比如宿主工程中,放了所有架構的目錄,包括了64位的,因為考慮外掛的大小,所以在外掛中只放了armeabi-v7a目錄的so檔案,如果裝置是64位的系統,那麼這時候外掛載入so檔案就會報錯。原因就在於上面分析的so相容問題中說到了,因為宿主工程中包含了64位的架構arm64-v8a型別,系統的abiList中也有arm64-v8a型別,所以這時候應用的ApplicationInfo的abi就是arm64-v8a了,那麼就會發送訊息給Zygote64的程序,建立的也是64位的虛擬機器了,而最後外掛中載入so的型別是32位的armeabi-v7a,那麼就會報錯了,因為32位的so檔案不能執行在64位的虛擬機器中的。
解決辦法:宿主工程和外掛工程中的so檔案的架構型別保持一致,這個將會帶來一個很大的問題,就是外掛包會變得很大,因為宿主工程為了相容多數機型,加入了多個型別的架構so檔案,但是外掛為了減小包大小,就放了指定型別的so檔案,但是最終會存在這種問題,所以這個解決辦法就要看專案需要了。
還有一個類似的問題:64-bit instead of 32-bit:
原理都是一樣的,32位的虛擬機器中載入了64位的so檔案問題導致的。
第三個問題:Shared library already opened
這個問題在上面介紹so載入流程中已經介紹過了,原因主要是因為之前使用DexClassLoader載入so之後,so沒有釋放還在記憶體中,而在此啟動有弄了一個新的DexClassLoader物件去載入so問題,就出錯了。
我們使用DexClassLoader類去載入外掛,但是因為我們為了外掛能夠實時更新,所以每次都會賦值新的DexClassLoader物件,但是第一次載入so檔案到記憶體中了,這時候退出程式,但是沒有真正意義上的退出,只是關閉了Activity了,這時候再次啟動又會賦值新的載入器物件,那麼原先so已經載入到記憶體中了,但是這時候是新的類載入器那麼就報錯了。
解決辦法:
第一種方式:在退出程式的時候採用真正意義上的退出,比如呼叫System.exit(0)方法,這時候程序被殺了,載入到記憶體的so也就被釋放了,那麼下次賦值新的類載入就在此載入so到記憶體了。
第二種方式:就是全域性定義一個static型別的類載入DexClassLoader也是可以的,因為static型別是儲存在當前程序中,如果程序沒有被殺就一直存在這個物件,下次進入程式的時候判斷當前類載入器是否為null,如果不為null就不要賦值了,但是這個方法有一個弊端就是類載入器沒有從新賦值,如果外掛這時候更新了,但是還是使用之前的載入器,那麼新外掛將不會進行載入。
十、技術概要
本文主要介紹了Android中關於so的相關知識,主要包括so編譯多架構問題,so載入流程問題,so釋放問題,so系統相容問題以及外掛中載入so檔案的功能解析,看完本文之後,我們需要了解到的知識點:
1、在NDK開發時,可以指定多種架構型別編譯出多種型別的so檔案。
2、so的載入流程主要是System類中的兩個載入方法,最終都會呼叫Runtime中的nativeLoad的native方法,而這個native方法最終會呼叫dlopen來開啟so檔案,然後在呼叫dlsym方法呼叫so的JNI_OnLoad方法。
3、關於apk檔案在安裝的時候釋放so檔案到本地目錄中,主要是結合當前裝置的abiList資訊(這個資訊主要是通過系統屬性:ro.product.cpu.abilist值來獲取的)和apk中不同型別架構,來決定最終釋放哪個型別目錄中的so檔案,釋放完成之後,還需要設定應用的nativeLib路徑,以及應用的abi資訊,因為這個abi資訊在後面啟動虛擬機器的時候需要用到。
4、因為現在有很多裝置已經是64位系統了,但是為了相容32位的so檔案,所以這些64位系統就會在系統啟動的時候建立兩個Zygote程序,一個是64位的,一個是32位的,當一個應用啟動的時候,需要建立虛擬機器,那麼這時候就會把應用的架構型別傳遞過去,系統會根據這個型別來交給哪個Zygote程序來處理這個應用啟動事件。這樣就可以做到so呼叫的相容問題了。
5、外掛中載入so檔案現階段主要有兩種方式,一種是先釋放外掛中的so檔案到本地目錄,然後設定DexClassLoader的nativeLib路徑;還有一種方式是先釋放外掛中的so檔案,然後呼叫System.load來載入全域性路徑的so檔案。
十一、問題總結
本文還總結了在使用so檔案的時候,會遇到的一些問題,主要是三個問題:
1、so檔案找不到問題
這個問題一般是因為我們忘記放了so檔案,或者是so檔案沒有放置全部,也就是沒有在libs目錄中所有的架構型別目錄中放置。
2、不同位數的虛擬機器運行了不同位數的so檔案
這個問題一般是因為我們在libs目錄中把so檔案放錯目錄了,或者是宿主工程和外掛工程中的so檔案架構型別目錄沒有保持一致。
3、類載入器載入so檔案再次載入
這個問題一般是因為外掛開發中使用了不同的DexClassLoader去載入多次相同的so檔案導致的。
十二、知識延展
我們在開發的過程中有時候想知道系統的位數,那麼這裡網上告知說有好幾種方法,其實那些都是忽悠人的,特別是在使用這個api的時候:android.os.Build.CPU_ABI,我就是在專案中被這個方法坑爹了,這個方法其實不是獲取系統的位數,而是獲取當前應用的架構型別位數,就是我們前面分析的ApplicationInfo中的abi資訊,我們可以檢視一下原始碼:
這裡可以看到,這個欄位已經被廢棄了,因為他不靠譜呀,這個欄位在Build類的static塊中進行賦值的:
這裡會通過VMRuntime類的is64Bit方法來判斷當前虛擬機器的位數,來獲取這個值
這裡還有兩個系統屬性:
ro.product.cpu.abilist32是32位的所有arch架構型別
ro.product.cpu.abilist64是64位的所有arch架構型別
而這兩個欄位值的合集就是前面的ro.product.cpu.abilist屬性值。
而VMRuntime的is64Bit方法是native方法,實現如下:
看到了,這裡得到的是虛擬機器的位數,那麼就是上面的Zygote程序的位數了。那麼問題就來了,假如我的裝置是64位的,但是我的專案中沒有arm64-v8a型別的so檔案,這時候在解析apk進行釋放so檔案的時候,就會得知架構型別是armeabi/armeabi-v7a了,因為遍歷apk檔案,沒有找到arm64-v8a型別的so檔案,這時候應用的abi型別就是armeabi/armeabi-v7a了,這就是32位的了,就會通知32位的Zygote程序建立了一個32位的虛擬機器,那麼此時我的專案中通過Build.CPU_ABI得到的系統位數就是32了,那麼完全不是我們想要的了。
所以正確的獲取系統位數的方法是:
Android5.0系統之後,可以通過ro.product.cpu.abilist屬性欄位值來判斷,如果這個欄位值中包含了64的話,那麼就是64位系統了
Android5.0系統之前,需要通過ro.product.cpu.abi屬性欄位值來判斷,不過5.0系統之前都是32位的,還沒有出現64位呢。
十三、選擇適當架構型別減小包大小
我們上面分析之後可以看到,如果想做到萬無一失即,專案不報錯,而且so執行效率也是非常高的話,就需要把那幾個架構型別的so檔案都要在專案中放一遍,那麼這個問題就來了,如果so檔案較大的話,apk包最終也是很大的,所以這裡就需要做一次選擇了。
1、我們在開發一個專案的時候因為,整個專案的so檔案結構我們可以控制,所以為了防止apk包增大,我們可以考慮只放幾個架構型別的so檔案,比如最好的是放armeabi型別的,因為首先現在大部分裝置採用cpu型號都是arm的,少數採用x86或者是mips型別的,其次是防止了armeabi型別之後,對於armeabi-v7a和arm64-v8a就可以相容了,不會存在報錯問題。但是因為系統需要相容所以就會出現so執行效率的問題了,最好的效率就是指定架構型別的so執行在對應架構型別的裝置中。因為現在大部分的裝置系統版本都是4.0以上了,所以armeabi-v7a架構型別用的比較多了,所以有時候為了效率問題,專案中只放了這個架構型別的so檔案,那麼像老版本的手機armeabi的話就會報錯了,當然這個錯誤是可以接受的即可。
2、有時候像x86和mips等少數型別架構的裝置,開發程式的時候會單獨出一個版本比如叫做xxx應用x86版本
3、在開發SDK的時候,因為開發之後的SDK包是給其他app接入的,而對於接入的app,我們不能做太多的限制,所以理論上應該把所有架構型別的so都要提供,這樣給需要接入的app進行選擇即可,比如像百度地圖SDK:
十四、總結
本文主要是介紹了Android中關於so的相關知識,而這些知識點都是在使用so檔案中會經常用到的,同時一些問題也是我們會遇到的,這裡只是做了一個總結,同時也給出了外掛中載入so檔案的方案已經遇到的問題解決思路等內容。