• Android动态加载so文件


    在Android中调用动态库文件(*.so)都是通过jni的方式,而且往往在apk或jar包中调用so文件时,都要将对应so文件打包进apk或jar包,工程目录下图:

    image

    以上方式的存在的问题:

    1、缺少灵活性比较类似静态加载了(不是静态加载),能加载的so文件绑定死了;

    2、但so文件很多或很大时,会导致对应的apk和jar包很大;

    3、不能动态的对so文件更新;

    Android中加载so文件的提供的API:

    void System.load(String pathName);

    说明:

    1、pathName:文件名+文件路劲;

    2、该方法调用成功后so文件中的导出函数都将插入的系统提供的一个映射表(类型Map);

    看到以上对System.load(String pathName);的函数说明可定有人会想到将so文件放到一个指定的目录然后再通过参数pathName直接引用该目录的路劲和对应的so文件问题不就解决了吗?

    这里有个问题被忽略了,那就是System.load只能加载两个目录路劲下的so文件:

    1、/system/lib ;

    2、安装包的路劲,即:/data/data/<packagename>/…

    而且这两个路劲又是有权限保护的不能直接访问;

    问题解决方法:

    先从网络下载so文件到手机目录(如:/test/device/test.so) –> 将test.so加载到内存(ByteArrayOutputStream) –> 然后保存到对用安装包目录;

    具体代码如下:

    try {
                String localPath = Environment.getExternalStorageDirectory() + path;
                Log.v(TAG, "LazyBandingLib localPath:" + localPath);

                String[] tokens = mPatterns.split(path);
                if (null == tokens || tokens.length <= 0
                        || tokens[tokens.length - 1] == "") {
                    Log.v(TAG, "非法的文件路径!");
                    return -3;
                }
                // 开辟一个输入流
                File inFile = new File(localPath);
                // 判断需加载的文件是否存在
                if (!inFile.exists()) {
                    // 下载远程驱动文件
                    Log.v(TAG, inFile.getAbsolutePath() + " is not fond!");
                    return 1;
                }
                FileInputStream fis = new FileInputStream(inFile);

                File dir = context.getDir("libs", Context.MODE_PRIVATE);
                // 获取驱动文件输出流
                File soFile = new File(dir, tokens[tokens.length - 1]);
                if (!soFile.exists()) {
                    Log.v(TAG, "### " + soFile.getAbsolutePath() + " is not exists");
                    FileOutputStream fos = new FileOutputStream(soFile);
                    Log.v(TAG, "FileOutputStream:" + fos.toString() + ",tokens:"
                            + tokens[tokens.length - 1]);

                    // 字节数组输出流,写入到内存中(ram)
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int len = -1;
                    while ((len = fis.read(buffer)) != -1) {
                        baos.write(buffer, 0, len);
                    }
                    // 从内存到写入到具体文件
                    fos.write(baos.toByteArray());
                    // 关闭文件流
                    baos.close();
                    fos.close();
                }
                fis.close();
                Log.v(TAG, "### System.load start");
                // 加载外设驱动
                System.load(soFile.getAbsolutePath());
                Log.v(TAG, "### System.load End");

                return 0;

            } catch (Exception e) {
                Log.v(TAG, "Exception   " + e.getMessage());
                e.printStackTrace();
                return -1;

    }

  • 相关阅读:
    Team Foundation Sidekicks 2010
    Asp.net页面传值的方式汇总
    轻量级IOC框架Ninject使用
    AutoMapper使用简单总结
    页面请求的方式(Get与Post)
    总结2012 规划2013
    在reset css后两个input之间还是出现默认间隔的问题。
    js学习笔记事件委托
    程序猿工具——svn
    JS 事件添加onclick写法注意。
  • 原文地址:https://www.cnblogs.com/jianyuan/p/4117876.html
Copyright © 2020-2023  润新知