一、背景
在开发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)实际机型测试可以正常使用,然后根据第四点列举问题完善以下,即可使用。