某些情況下安卓引入so衝突的解決
阿新 • • 發佈:2018-11-22
前言
年前在做一個專案的時候,為了減小apk的大小,所以就把除了'armeabi'的so都給刪了,經測試無不良情況.
前一段時間又要改某個sdk,換了一個so庫,必須要用64位的(arm64v8a),由於專案時間長了,換了次svn地址,所以就悲劇了,專案以前的64位so都被刪了也找不回來了,而新so庫必須要用64位的,這下就有問題了(加入arm64v8a,就需要其他so也支援64位的,直接把64位的放到armabi下引入會報錯)
解決方案
後來想到loadLibrary的方法有兩個:
1.System.loadLibrary
該方法直接去jniLibs資料夾內尋找so並載入.
比如:jniLibs/armabi/libSDK.so 呼叫方法為:System.loadLibrary("SDK"); 需要掐頭去尾
2.System.load
該方法可以載入本地File路徑的形式載入
於是可以把so檔案放在本地,一般來說一種通過網路下載到本地,另一種通過assets資原始檔的形式複製到本地,我選用第二種方式
程式碼實現
assets資源拷貝到本地的工具類
import android.content.Context; import android.content.res.AssetManager; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; public class AssetCopyer { private String asset_list_fileName; private final Context mContext; private final AssetManager mAssetManager; private File mAppDirectory; public AssetCopyer(Context context, String asset_list_fileName) { mContext = context; mAssetManager = context.getAssets(); this.asset_list_fileName = asset_list_fileName; } /** * 將assets目錄下指定的檔案拷貝到sdcard中 * * @return 檔案列表 // * @return 是否拷貝成功, true 成功;false 失敗 * @throws IOException */ public List<File> copy() throws IOException { List<String> srcFiles = new ArrayList<>(); //獲取系統在SDCard中為app分配的目錄,eg:/sdcard/Android/data/$(app's package) //該目錄存放app相關的各種檔案(如cache,配置檔案等),unstall app後該目錄也會隨之刪除 mAppDirectory = mContext.getExternalFilesDir(null); if (null == mAppDirectory) { return null; } //讀取assets/$(subDirectory)目錄下的assets.lst檔案,得到需要copy的檔案列表 List<String> assets = getAssetsList(); for (String asset : assets) { //如果不存在,則新增到copy列表 if (!new File(mAppDirectory, asset).exists()) { srcFiles.add(asset); } } List<File> fileList=new ArrayList<>(); //依次拷貝到App的安裝目錄下 for (String file : srcFiles) { fileList.add(copy(file)); } return fileList; } /** * 獲取需要拷貝的檔案列表(記錄在assets/assets.lst檔案中) * * @return 檔案列表 * @throws IOException */ protected List<String> getAssetsList() throws IOException { List<String> files = new ArrayList<>(); /*InputStream listFile = mAssetManager.open(new File(asset_list_fileName).getPath()); BufferedReader br = new BufferedReader(new InputStreamReader(listFile)); String path; while (null != (path = br.readLine())) { files.add(path); }*/ //todo 懶省事,就不用資源內的檔案,而是直接用so檔名字進行拼接了 for (String s : asset_list_fileName.split("##")) files.add(s); return files; } /** * 執行拷貝任務 * * @param asset 需要拷貝的assets檔案路徑 * @return 拷貝成功後的目標檔案控制代碼 * @throws IOException */ protected File copy(String asset) throws IOException { InputStream source = mAssetManager.open(new File(asset).getPath()); File destinationFile = new File(mAppDirectory, asset); if (destinationFile.exists()) { return destinationFile; } destinationFile.getParentFile().mkdirs(); OutputStream destination = new FileOutputStream(destinationFile); byte[] buffer = new byte[1024]; int nread; while ((nread = source.read(buffer)) != -1) { if (nread == 0) { nread = source.read(); if (nread < 0) break; destination.write(nread); continue; } destination.write(buffer, 0, nread); } destination.close(); return destinationFile; } }
先把有相應的so檔案放入assets資料夾中
然後呼叫工具類拷貝so檔案,呼叫System.load()方法來載入相應的so檔案
String files = "libIAL.so##libSDL.so"; List<File> copy = new AssetCopyer(context, files).copy(); for (File f : copy) System.load(f.getAbsolutePath());
然後成功的引入了so檔案