转自: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; }