Android 开发中如何动态加载 so 库文件(转载)
动态加载的优点
静态加载,不灵活,apk 包有可能大。所以采用动态加载 so 库文件,有以下几点好处:
- 灵活,so 文件可以动态加载,不是绑定死的,修改方便,so 库有问题,我们可以动态更新。
- so 库文件很大的话,采用动态加载可以减少 apk 的包,变小。
- 其实我们常用第三方 so 库,单个可能没问题,如果多个第三方 so 库文件,同时加载可能会出现冲突,而动态加载就能够解决这一问题。
注意路径陷阱
动态加载 so 库文件,并不是说可以把文件随便存放到某个 sdcard 文件目录下,这样做既不安全,系统也加载不了。
我们在 Android 中加载 so 文件,提供的 API 如下:
//第一种,pathName 库文件的绝对路径
void System.load(String pathName);
//第二种,参数为库文件名,不包含库文件的扩展名,必须是在JVM属性Java.library.path所指向的路径中,路径可以通过System.getProperty('java.library.path') 获得
void loadLibrary(String libname)
注意:而这里加载的文件路径只能加载两个目录下的 so 文件。那就是:
- /system/lib
- 应用程序安装包的路径,即:/data/data/packagename/…
所以,so 文件动态加载的文件目录不能随便放。这是需要注意的一点。
实现思路
既然使用动态加载的好处和陷阱我们都大致了解了,那就可以在实现的时候,注意陷阱就可以了。那基本思路如下:
- 网络下载 so 文件到指定目录
- 从指定下载的目录复制 copy so文件到可动态加载的文件目录下,比如:/data/data/packagename/…
- 配置 gradle ,指定 cpu 架构
- load 加载
第一步,我们这里可以简单忽略,假设我们把 so 文件下载到了 /mnt/sdcard/armeabi 目录下。
复制目录到包路径下
那我们就应该把 /mnt/sdcard/armeabi 目录下的 so 文件,复制到 应用的包路径下。
/**
* Created by loonggg on 2017/3/29.
*/
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