Android 加载sdcard中的so库
项目背景
最近项目与第三方合作,对方提供so接口,我们进行实现,要求我们将so库放在sdcard中。
我们知道sdcard中的so没有执行权限,那么直接通过dlopen打开sdcard中so的方式并不可取。不得已,在网上找的一种解决方法:将sdcard中的so库拷贝到应用的私有libs库,然后再使用dlopen方式进行打开。
当然dlopen是在c/c++里面进行调用的,如果我们需要java层面进行调用的话,可以使用System.load方法。
实现
1.拷贝sdcard so至 应用私有libs中
工具类方法如下:
public class NativeLibraryLoader {
public static boolean loadLibrary(Context context, String libPath, String libName) {
// 获取应用的私有模式的libs目录。
File libs_dir = context.getDir("libs", Context.MODE_PRIVATE);
Log.e("NativeLibraryLoader", libs_dir.getAbsolutePath());
String new_file_name = libs_dir.getPath() + "/" + libName;
String old_file_name = libPath + "/" + libName;
if (!copyLibrary(new_file_name, old_file_name)) {
Log.e("NativeLibraryLoader", "copy Library failed");
return false;
}
try {
System.load(new_file_name);
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
return true;
}
//项目中会拷贝sdcard中的so库至私有目录
public static boolean copyLibrary(String new_file_name, String old_file_name) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File new_file = new File(new_file_name);
File old_file = new File(old_file_name);
/* delete old library if exists. */
if (new_file.exists()) new_file.delete();
fis = new FileInputStream(old_file);
fos = new FileOutputStream(new_file);
int dataSize;
byte[] dataBuffer = new byte[2048];
while ((dataSize = fis.read(dataBuffer)) != -1) {
fos.write(dataBuffer, 0, dataSize);
}
fos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fos != null) fos.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
if (fis != null) fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
}
在测试过程中,为了查看我们私有模式的libs路径,进行了打印,其中xxx.xxx.xxx为应用包名。
使用了几部手机,都是如下路径。
E/NativeLibraryLoader: /data/user/0/xxx.xxx.xxx/app_libs
2.加载so库
NativeLibraryLoader.loadLibrary(this, "/mnt/sdcard", "libnative-lib.so");
总结
其实这种使用方式并不被推荐,仅考虑一种情况:so库放在sdcard中如果被用户误删的情况下如何处理。
因为是第三方要求如此处理,我也没有办法。只好如此了。