標籤:android style blog http io ar os sp 檔案
在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;
}
Android動態載入so檔案