一、背景
在開發Android應用程序的實現,有時候需要引入第三方so lib庫,但第三方so庫比較大,例如開源第三方播放組件ffmpeg庫, 如果直接打包的apk包里面, 整個應用程序會大很多.經過查閱資料和實驗,發現通過遠程下載so文件,然后再動態注冊so文件時可行的。主要需要解決下載so文件存放位置以及文件讀寫權限問題。
二、主要思路
1、首先把so放到網絡上面,比如測試放到:http://codestudy.sinaapp.com/lib/test.so
2、應用啟動時,啟動異步線程下載so文件,並寫入到/data/data/packageName/app_libs目錄下面
3、調用System.load 注冊so文件。因路徑必須有執行權限,我們不能加載SD卡上的so,但可以通過調用context.getDir("libs", Context.MODE_PRIVATE)把so文件寫入到應用程序的私有目錄/data/data/packageName/app_libs。
三、代碼實現
1、網絡下載so文件,並寫入到應用程序的私有目錄/data/data/PackageName/app_libs
/**
* 下載文件到/data/data/PackageName/app_libs下面
* @param context
* @param url
* @param fileName
* @return
*/
public static File downloadHttpFileToLib(Context context, String url, String fileName) {
long start = System.currentTimeMillis();
FileOutputStream outStream = null;
InputStream is = null;
File soFile = null;
try {
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
File dir = context.getDir("libs", Context.MODE_PRIVATE);
soFile = new File(dir, fileName);
outStream = new FileOutputStream(soFile);
is = entity.getContent();
if (is != null) {
byte[] buf = new byte[1024];
int ch = -1;
while ((ch = is.read(buf)) > 0) {
outStream.write(buf, 0, ch);
//Log.d(">>>httpDownloadFile:", "download 進行中....");
}
}
outStream.flush();
long end = System.currentTimeMillis();
Log.d(">>>httpDownloadFile cost time:", (end-start)/1000 + "s");
Log.d(">>>httpDownloadFile:", "download success");
return soFile;
} catch (IOException e) {
Log.d(">>>httpDownloadFile:", "download failed" + e.toString());
return null;
} finally {
if (outStream != null) {
try {
outStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2、調用System.load 注冊so文件
new Thread(new Runnable() {
@Override
public void run() {
File soFile = FileUtils.downloadHttpFileToLib(getApplicationContext(), "http://codestudy.sinaapp.com//lib/test.so", "test.so");
if (soFile != null) {
try {
Log.d(">>>loadAppFile load path:", soFile.getAbsolutePath());
System.load(soFile.getAbsolutePath());
} catch (Exception e) {
Log.e(">>>loadAppFile load error:", "so load failed:" + e.toString());
}
}
}
}).start();
四、需要解決的問題
1、so文件下載以及注冊時機。測試發現libffmpeg.so 8M的文件單線程下載需要10-13s左右
2、so下載失敗或者注冊失敗該怎么處理。例如so播放組件是否嘗試采用android系統原生MediaPlayer進行播放
3、當初次so還沒有下載完注冊成功時,進入播放頁面時,需要友好提示用戶,比如loading 視頻正在加載等等
4、無網絡情況等等情況
五、說明
上面的demo經過3(2.3/4.2/4.4)實際機型測試可以正常使用,然后根據第四點列舉問題完善以下,即可使用。
