動態引入so庫
為什么要動態引入so庫?
遇到的問題:因為要做一些系統級別的工具,所以要調用一些系統的so庫,如果把so庫直接放在lib目錄下的話,在android程序啟動的時候會默認加載lib目錄下的所有庫,但是這些so庫會在一些地方存在沖突,所以為了解決這個沖突的問題,就使用動態加載so庫的方式,通過一些條件的判斷是否要加載這個so庫。
如何動態加載so庫?
1.首先把so庫放在assets資源目錄下,一般會放兩個so庫,一個32位一個64位的
2.動態加載,就是在需要使用的時候,從assets資源目錄下復制到app-libs目錄下
public static boolean loadLibrary(Context context, String oldFileName, String libName) throws IOException {
// 獲取應用的私有模式的libs目錄(真實的目錄是app-libs)
File libs_dir = context.getDir("libs", Context.MODE_PRIVATE);
// 可以獲取到assets資源文件的數據流
InputStream open = context.getAssets().open(oldFileName);
String new_file_name = libs_dir.getPath() + "/" + libName;
// 把資源文件的數據流寫入到app-libs目錄下
if (!copyLibrary(open, new_file_name)) {
return false;
}
try {
System.load(new_file_name);
} catch (Exception ex) {
ex.printStackTrace();
return false;
}
return true;
}
//從assets資源目錄下復制到app-libs目錄下
public static boolean copyLibrary(InputStream fileInputStream, String new_file) {
FileOutputStream fos = null;
try {
File file = new File(new_file);
fos = new FileOutputStream(file);
int dataSize;
byte[] dataBuffer = new byte[2048];
while ((dataSize = fileInputStream.read(dataBuffer)) != -1) {
fos.write(dataBuffer, 0, dataSize);
}
fos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
Log.e("NativeLibraryLoader",e.getMessage());
} finally {
try {
if (fos != null) fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return false;
}
3.判斷系統是多少位的然后在靜態代碼塊里加載不同的so庫
static {
//注冊
try {
Context context = MainApplication.getContextObject();
String osName = "lib32.so";
//如果這個SUPPORTED_ABIS包含64就是64位的系統
if (SUPPORTED_ABIS[0].contains("64")) {
osName = "lib64.so";
}
NativeLibraryLoader.loadLibrary(context, osName, "libtv.so");
} catch (Exception e) {
e.printStackTrace();
}
}
4.存在問題
在沒有關閉selinux的情況下,System.load(xxxx.so)會因為權限的原因導致失敗 Permission denied;
如果權限夠的話,可以直接使用暴力的方法,直接把assert目錄的文件直接復制到lib目錄下,然后使用System.loadLibrary(libsitatv.so)就能直接加載