1. 程式人生 > >某些情況下安卓引入so衝突的解決

某些情況下安卓引入so衝突的解決

前言

年前在做一個專案的時候,為了減小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檔案