Android 开发中如何动态加载 so 库文件
2018-01-05 18:22
447 查看
动态加载的优点
静态加载,不灵活,apk 包有可能大。所以采用动态加载 so 库文件,有以下几点好处:
灵活,so 文件可以动态加载,不是绑定死的,修改方便,so 库有问题,我们可以动态更新。
so 库文件很大的话,采用动态加载可以减少 apk 的包,变小。
其实我们常用第三方 so 库,单个可能没问题,如果多个第三方 so 库文件,同时加载可能会出现冲突,而动态加载就能够解决这一问题。
注意路径陷阱
动态加载 so 库文件,并不是说可以把文件随便存放到某个 sdcard 文件目录下,这样做既不安全,系统也加载不了。
我们在 Android 中加载 so 文件,提供的 API 如下:
注意:而这里加载的文件路径只能加载两个目录下的 so 文件。那就是:
/system/lib
应用程序安装包的路径,即:/data/data/packagename/…
所以,so 文件动态加载的文件目录不能随便放。这是需要注意的一点。
实现思路
既然使用动态加载的好处和陷阱我们都大致了解了,那就可以在实现的时候,注意陷阱就可以了。那基本思路如下:
网络下载 so 文件到指定目录
从指定下载的目录复制 copy so文件到可动态加载的文件目录下,比如:/data/data/packagename/…
配置 gradle ,指定 cpu 架构
load 加载
第一步,我们这里可以简单忽略,假设我们把 so 文件下载到了 /mnt/sdcard/armeabi 目录下。
那我们就应该把 /mnt/sdcard/armeabi 目录下的 so 文件,复制到 应用的包路径下。
我们都知道,在使用 so 文件的时候,so 库类型和 CPU 架构类型,要一致,否则是会报错的。原因很简单,不同 CPU 架构的设备需要用不同类型 so 库。CPU架构有如下几种类型:ARMv5,ARMv7,x86,MIPS,ARMv8,MIPS64 和 x86_64。如果要适配很多手机,就需要在不同的类型下,放置对应的 so 文件。
配置方法如下:
复制到可加载使用的包路径下后,配置完 gradle 之后,就可以使用 load API 调用了。
这样,我们就实现了动态加载 so 文件。
欢迎大家关注我的技术分享公众号:非著名程序员(smart_android)。技术文章均先首发于我的技术分享的微信公众号。
作者: 涩郎_非著名程序员
链接:http://www.imooc.com/article/17298
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作!
静态加载,不灵活,apk 包有可能大。所以采用动态加载 so 库文件,有以下几点好处:
灵活,so 文件可以动态加载,不是绑定死的,修改方便,so 库有问题,我们可以动态更新。
so 库文件很大的话,采用动态加载可以减少 apk 的包,变小。
其实我们常用第三方 so 库,单个可能没问题,如果多个第三方 so 库文件,同时加载可能会出现冲突,而动态加载就能够解决这一问题。
注意路径陷阱
动态加载 so 库文件,并不是说可以把文件随便存放到某个 sdcard 文件目录下,这样做既不安全,系统也加载不了。
我们在 Android 中加载 so 文件,提供的 API 如下:
//第一种,pathName 库文件的绝对路径 void System.load(String pathName); //第二种,参数为库文件名,不包含库文件的扩展名,必须是在JVM属性Java.library.path所指向的路径中,路径可以通过System.getProperty('java.library.path') 获得 void loadLibrary(String libname)
注意:而这里加载的文件路径只能加载两个目录下的 so 文件。那就是:
/system/lib
应用程序安装包的路径,即:/data/data/packagename/…
所以,so 文件动态加载的文件目录不能随便放。这是需要注意的一点。
实现思路
既然使用动态加载的好处和陷阱我们都大致了解了,那就可以在实现的时候,注意陷阱就可以了。那基本思路如下:
网络下载 so 文件到指定目录
从指定下载的目录复制 copy so文件到可动态加载的文件目录下,比如:/data/data/packagename/…
配置 gradle ,指定 cpu 架构
load 加载
第一步,我们这里可以简单忽略,假设我们把 so 文件下载到了 /mnt/sdcard/armeabi 目录下。
复制目录到包路径下
那我们就应该把 /mnt/sdcard/armeabi 目录下的 so 文件,复制到 应用的包路径下。/** * Created by loonggg on 2017/3/29. */ public class SoFile { /** * 加载 so 文件 * @param context * @param fromPath 下载到得sdcard目录 */ public static void loadSoFile(Context context, String fromPath) { File dir = context.getDir("libs", Context.MODE_PRIVATE); if (!isLoadSoFile(dir)) { copy(fromPath, dir.getAbsolutePath()); } } /** * 判断 so 文件是否存在 * @param dir * @return */ public static boolean isLoadSoFile(File dir) { File[] currentFiles; currentFiles = dir.listFiles(); boolean hasSoLib = false; if (currentFiles == null) { return false; } for (int i = 0; i < currentFiles.length; i++) { if (currentFiles[i].getName().contains("libwedsa23")) { hasSoLib = true; } } return hasSoLib; } /** * * @param fromFile 指定的下载目录 * @param toFile 应用的包路径 * @return */ public static int copy(String fromFile, String toFile) { //要复制的文件目录 File[] currentFiles; File root = new File(fromFile); //如同判断SD卡是否存在或者文件是否存在,如果不存在则 return出去 if (!root.exists()) { return -1; } //如果存在则获取当前目录下的全部文件 填充数组 currentFiles = root.listFiles(); //目标目录 File targetDir = new File(toFile); //创建目录 if (!targetDir.exists()) { targetDir.mkdirs(); } //遍历要复制该目录下的全部文件 for (int i = 0; i < currentFiles.length; i++) { if (currentFiles[i].isDirectory()) { //如果当前项为子目录 进行递归 copy(currentFiles[i].getPath() + "/", toFile + currentFiles[i].getName() + "/"); } else { //如果当前项为文件则进行文件拷贝 if (currentFiles[i].getName().contains(".so")) { int id = copySdcardFile(currentFiles[i].getPath(), toFile + File.separator + currentFiles[i].getName()); } } } return 0; } //文件拷贝 //要复制的目录下的所有非子目录(文件夹)文件拷贝 public static int copySdcardFile(String fromFile, String toFile) { try { FileInputStream fosfrom = new FileInputStream(fromFile); FileOutputStream fosto = new FileOutputStream(toFile); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = -1; while ((len = fosfrom.read(buffer)) != -1) { baos.write(buffer, 0, len); } // 从内存到写入到具体文件 fosto.write(baos.toByteArray()); // 关闭文件流 baos.close(); fosto.close(); fosfrom.close(); return 0; } catch (Exception ex) { return -1; } } }
配置 grade 指定 cpu 架构
我们都知道,在使用 so 文件的时候,so 库类型和 CPU 架构类型,要一致,否则是会报错的。原因很简单,不同 CPU 架构的设备需要用不同类型 so 库。CPU架构有如下几种类型:ARMv5,ARMv7,x86,MIPS,ARMv8,MIPS64 和 x86_64。如果要适配很多手机,就需要在不同的类型下,放置对应的 so 文件。配置方法如下:
defaultConfig { applicationId "xxxx" minSdkVersion 17 targetSdkVersion 25 versionCode 1 versionName "1.0" ndk { abiFilters "armeabi","armeabi-v7a","x86" } }
load 加载 so 文件
复制到可加载使用的包路径下后,配置完 gradle 之后,就可以使用 load API 调用了。File dir = getApplicationContext().getDir("libs", Context.MODE_PRIVATE); File[] currentFiles; currentFiles = dir.listFiles(); for (int i = 0; i < currentFiles.length; i++) { System.load(currentFiles[i].getAbsolutePath()); }
这样,我们就实现了动态加载 so 文件。
欢迎大家关注我的技术分享公众号:非著名程序员(smart_android)。技术文章均先首发于我的技术分享的微信公众号。
作者: 涩郎_非著名程序员
链接:http://www.imooc.com/article/17298
来源:慕课网
本文原创发布于慕课网 ,转载请注明出处,谢谢合作!
相关文章推荐
- Android设备如何加载.so文件以及如何适配
- CrossWalk - android 动态加载so库文件实践
- CrossWalk - Android 动态加载so库文件
- Android动态加载so文件
- Android JNI学习笔记——so文件动态加载
- Notes开发如何动态加载dll文件
- (4.1.27.11)Android动态加载so文件
- Android插件化开发基础之App如何动态加载类
- Android动态加载so文件
- Android动态加载包含so文件的jar的自定义view控件
- Android开发中如何将自己编译的.so文件用到其他的项目中
- Android动态加载so文件
- Android 如何动态加载 .jar
- Android腾讯微博客户端开发五:利用FootView实现ListView滑动动态加载实现分页
- Android腾讯微博客户端开发5:利用FootView实现ListView滑动动态加载实现分页
- 如何用gdb找到Android so文件中的加密key
- Android Eclipse JNI 调用 .so文件加载问题
- 转:Android App 如何动态加载类
- 如何按需动态加载js文件
- 水晶报表中如何动态加载图片(图片文件版本及数据库版本)