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