智慧 + 毅力 = 无所不能

正确性、健壮性、可靠性、效率、易用性、可读性、可复用性、兼容性、可移植性...
随笔 - 991, 文章 - 0, 评论 - 27, 阅读 - 341万

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

Android动态加载so文件

Posted on   Bill Yuan  阅读(30994)  评论(0编辑  收藏  举报

转自:http://www.shaoqun.com/a/105310.aspx

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

以上方式的存在的问题:

  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; 

}
复制代码

 

(评论功能已被禁用)
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示