美文网首页Android JNI
android动态的加载so库文件

android动态的加载so库文件

作者: 圈圈猫 | 来源:发表于2017-03-30 16:16 被阅读4148次

    昨天突然之间看到linux加载so,然后同事突然问我android怎么加载的,然后我但是也懵逼了,so库不是在本地加载的吗?然后他说不是,然后就去查了下,我们平时用的都是在main/jniLibs下的*.so文件。于是就找了下,有大神些过。然而我当时也不懂,看了就记录下来。
    支持原创:http://mp.weixin.qq.com/s/MjVnODQkk5rBFxHt4jA4NQ

    在android中加载so有两种方式。

    静态加载

    其实静态方式就是将so包和apk或者jar的方式打包在一起,这样就导致了不灵活,apk包可能比较大。

    动态加载

    动态加载的优点

    1、灵活,so库可以动态的更新。
    2、so如果比较大的话可以减少apk的大小
    3、解决了多个第三方的so库文件同时加载造成的冲突。

    注意事项:

    android提供给了api:

    //第一种。pathName库文件的绝对路径
    viod Sytem.load(String pathName);
    //第二种,参数为库文件名,不包含库文件的扩展名,必须是在JVM属性Java.library.path所指向的路径中,路径可以通过System.getProperty('java.library.path') 获得
    void loadLibrary(String libName);
    

    注意:这里加载的文件路劲只能加载两个so文件:

    • 1、/system/lib
    • 2、应用程序安装包的路径: /data/data/packagename

    在这之前我也是听懵逼的,如果是下载然后在本地是如何引入so的,接着往下看实现思路:
    1、网络下载so文件到指定目录
    2、从指定下载的目录复制copy so文件到可动态加载的文件目录下。/data/data/packageName
    3、配置gradle,指定cpu架构
    4、load加载

    1、下载so

    这个应该都懂,用okhttp下载,假设下载的路径是/mnt/sdcard/armeabi 目录

    2、复制目录到包路径下

    把/mnt/sdcard/armeabi目录下的so文件,复制到应用的包路径下。

    public class SoFile {
        /**
         * 加载 so 文件
         * @param context
         * @param fromPath 下载到得sdcard目录
         */
        public static void loadSoFile(Context context, String fromPath) {
            File dir = context.getDir("libs", Context.MODE_PRIVATE);
            if (!isLoadSoFile(dir)) {
                copy(fromPath, dir.getAbsolutePath());
            }
        }
    
        /**
         * 判断 so 文件是否存在
         * @param dir
         * @return
         */
        public static boolean isLoadSoFile(File dir) {
            File[] currentFiles;
            currentFiles = dir.listFiles();
            boolean hasSoLib = false;
            if (currentFiles == null) {
                return false;
            }
            for (int i = 0; i < currentFiles.length; i++) {
                if (currentFiles[i].getName().contains("libwedsa23")) {
                    hasSoLib = true;
                }
            }
            return hasSoLib;
        }
    
        /**
         *
         * @param fromFile 指定的下载目录
         * @param toFile 应用的包路径
         * @return
         */
        public 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());
                    }
                }
            }
            return 0;
        }
    
    
        //文件拷贝
        //要复制的目录下的所有非子目录(文件夹)文件拷贝
        public 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;
            }
        }
    }
    
    3、gradle指定cpu架构
    defaultConfig {
    
            ndk {
                abiFilters "armeabi","armeabi-v7a","x86"
            }
        }
    
    4、load加载so文
    File dir =  getApplicationContext().getDir("l  ibs", Context.MODE_PRIVATE);
    File[] currentFiles;currentFiles = dir.listFiles();
    for (int i = 0; i < currentFiles.length; i++) {
       System.load(currentFiles[i].getAbsolutePath());
    }
    

    ok~就这样实现了动态的加载so库。

    相关文章

      网友评论

        本文标题:android动态的加载so库文件

        本文链接:https://www.haomeiwen.com/subject/emcpottx.html