动态加载sd卡或者手机内置存储卡的so库

package com.wsc.utils;

import android.content.Context;

import com.wsc.common.Entrance;
import com.wsc.common.SDKCommon;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * so库从sd卡拷贝到app的私有目录下,并进行比对验证和加载<p></p>
 * Created by win10-JYcainiao on 2018/1/24.
 */

public class LoadSoFileUtils {
    private static final String TAG = LoadSoFileUtils.class.getSimpleName();

    /**
     * 加载 so 文件
     *
     * @param context
     * @param soPath  下载到得sdcard目录
     */
    public static void loadSoFile(Context context, String soPath, LoadSoFileListener loadSoFileListener) throws Exception {
        if (Entrance.loacSo) {
            KLog.d(TAG, "so已经加载过了");
            return;
        }
        //存放so文件的私有目录
        File appLibs = context.getApplicationContext().getDir("libs", Context.MODE_PRIVATE);
        //需要加载的so文件
        File soDir = new File(soPath);
        File[] soFiles = null;
        //获取so来源文件夹下的所有so文件
        if (soDir.exists() && soDir.isDirectory()) {
            soFiles = soDir.listFiles();
        }
        //看看需要加载的so文件
        if (!soFileExisted(appLibs, soFiles) && soFiles != null) {
            copy(soPath, appLibs.getAbsolutePath());
        }
        //获取app私有目录下的文件列表
        File[] currentFiles = appLibs.listFiles();
        if (!loadSoFileListener.compareSo(currentFiles)) {
            KLog.d(TAG, "so验证未通过");
            loadSoFileListener.onError();
            return;
        }
        //记录加载的so个数
        int loacSoFileCount = 0;
        //根据so文件名称加载so文件
        for (int i = 0; i < currentFiles.length; i++) {
            for (int j = 0; j < SDKCommon.soFileNames.length; j++) {
                if (currentFiles[i].getName().contains(SDKCommon.soFileNames[j])) {
                    try {
                        System.load(currentFiles[i].getAbsolutePath());
                        loacSoFileCount++;
                    } catch (Exception e) {
                        throw new Exception("加载so库失败,soName = " + currentFiles[i].getName());
                    }
                }
            }
        }
        //判断需要加载的so是否加载完全
        if (loacSoFileCount == SDKCommon.soFileNames.length) {
            Entrance.loacSo = true;
            loadSoFileListener.onSuccess();
        } else {
            loadSoFileListener.onError();
        }
    }

    /**
     * 判断 so 文件是否存在
     *
     * @param soFolder 需要存放so库的app私有文件夹
     * @param soFiles  需要动态加载的so文件
     * @return 需要加载的so文件是否存在
     */
    private static boolean soFileExisted(File soFolder, File... soFiles) {
        int count = 0;
        if (soFolder.exists()) {
            File[] files = soFolder.listFiles();
            if (files != null && files.length > 0) {
                for (int i = 0; i < files.length; i++) {
                    for (int j = 0; j < soFiles.length; j++) {
                        if (files[i].getName().equals(soFiles[j].getName()) && files[i].length() == soFiles[j].length()) {
                            count++;
                        }
                    }
                }
            }
        }
        if (count == 6) {
            return true;
        }
        return false;
    }

    /**
     * @param fromFile 指定的下载目录
     * @param toFile   应用的包路径
     * @return
     */
    private static int copy(String fromFile, String toFile) {
        //要复制的文件目录
        File[] currentFiles;
        File root = new File(fromFile);
        //如同判断SD卡是否存在或者文件是否存在,如果不存在则 return出去
        if (!root.exists()) {
            return -1;
        }
        //如果存在则获取当前目录下的全部文件 填充数组
        currentFiles = root.listFiles();
        //目标目录
        File targetDir = new File(toFile);
        //创建目录
        if (!targetDir.exists()) {
            targetDir.mkdirs();
        }
        //遍历要复制该目录下的全部文件
        for (int i = 0; i < currentFiles.length; i++) {
            if (currentFiles[i].isDirectory()) {
                //如果当前项为子目录 进行递归
                copy(currentFiles[i].getPath() + "/", toFile + currentFiles[i].getName() + "/");
            } else {
                //如果当前项为文件则进行文件拷贝
                if (currentFiles[i].getName().contains(".so")) {
                    int id = copySdcardFile(currentFiles[i].getPath(), toFile + File.separator + currentFiles[i].getName());
                    KLog.d(TAG, currentFiles[i].getName());
                }
            }
        }
        return 0;
    }

    //文件拷贝
    //要复制的目录下的所有非子目录(文件夹)文件拷贝
    private static int copySdcardFile(String fromFile, String toFile) {
        try {
            FileInputStream fosfrom = new FileInputStream(fromFile);
            FileOutputStream fosto = new FileOutputStream(toFile);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = -1;
            while ((len = fosfrom.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }
            // 从内存到写入到具体文件
            fosto.write(baos.toByteArray());
            // 关闭文件流
            baos.close();
            fosto.close();
            fosfrom.close();
            return 0;
        } catch (Exception ex) {
            return -1;
        }
    }

    public interface LoadSoFileListener {
        void onSuccess();

        void onError();

        /**
         * 验证so
         *
         * @param loadSofile 需要验证的so
         */
        boolean compareSo(File... loadSofile);
    }
}

  

posted @ 2018-01-25 18:46  凤雏小呆  阅读(829)  评论(0编辑  收藏  举报