Android动态加载—Res文件
2016-04-05 21:33
369 查看
简介
动态加载res文件,就是将资源文件打包进一个统一的apk,而在我们的app安装后通过后台下载,然后再写到我们的应用中,将这个含有资源的apk,可以称为插件apk,而我们的app,可以称为宿主apk,在宿主中加载插件中的资源文件的方法。介绍
下载加载
获取资源文件
对于下载可以参考上一篇so文件的下载,没什么要说的,加载是从你的sdcard目录下复制到你的应用目录下例如:data/data/包名/app_dex目录下面,代码参考so文件的复制。
将apk复制到指定的目录后,就是获取其里面的资源了,而获取一个应用的资源,我么首先要知道这个资源对应的id是多少,而对于插件来说,它里面的资源id我们是不知道的,但是资源的name确实我们开发者定的,所有我们可以通过资源的name来获取id,方法是系统API : Resources.getIdentifier()
public int getIdentifier(String name, String defType, String defPackage) { if (name == null) { throw new NullPointerException("name is null"); } try { return Integer.parseInt(name); } catch (Exception e) { // Ignore } return mAssets.getResourceIdentifier(name, defType, defPackage); }
好了,拿到了资源id,我们就可以应用到我们需要的地方了。但是,在运行的时候你会发现获取的id是0,这是因为你用的Resources是宿主的resources,在宿主里面并没有找到你name所对应的id。所以,我们还需要创建一个插件所拥有的resources,让app拥有两个resources对象,当加载插件资源的时候用插件的resources
protected void loadResources(File tmpDir) { try { File[] currentFiles=tmpDir.listFiles(); String path; if (currentFiles == null || currentFiles.length == 0) { path = DuduUtil.resApkPath; } else { path = currentFiles[0].getAbsolutePath(); } AssetManager assetManager = AssetManager.class.newInstance(); Method addAssetPath = assetManager.getClass().getMethod( "addAssetPath", String.class);//通过methodName和参数的数据类型得到要执行的Method。 addAssetPath.invoke(assetManager, path);//assetManager对象中带有参数path的addAssetPath方法。返回值是Object,也既是该方法的返回值 mAssetManager = assetManager; } catch (Exception e) { e.printStackTrace(); } Resources superRes = super.getResources(); mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration()); }
解释一下反射的两个方法的意思:
getMethod
public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException { return getMethod(name, parameterTypes, true); }
@param name
* the requested method’s name.
* @param parameterTypes
* the parameter types of the requested method.
* {@code (Class[]) null} is equivalent to the empty array.
Method字面理解方法的意思,getMethod参数的意思,name:方法的名字;parameterTypes方法参数的类型,获取assetManager对象里面名字为addAssetPath,参数类似为String的方法,即:
public final int addAssetPath(String path) { synchronized (this) { int res = addAssetPathNative(path); makeStringBlocks(mStringBlocks); return res; } }
invoke
@param receiver the object on which to call this method (or null for static methods) @param args the arguments to the method public native Object invoke(Object receiver, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
invoke字面理解:调用。receiver调用反射处理的method,参数是args
至此,插件apk的resources已经拿到,然后再通过name拿到id,但是拿到id之后并不能直接使用,因为我们之前直接setxxx(id)的时候,实在方法里面转换成了相应的资源,所以,还需要我们把插件的资源转换成向对应的资源
demo:https://github.com/fayou147/DyLoadResDemo
相关文章推荐
- Android编程获取sdcard音乐文件的方法
- 自定义 View 基础和原理
- Android--登录界面
- Android--通知之Notification
- Android 5 及之后版本rom解包
- Android中Intent传递对象的两种方法(Serializable,Parcelable)
- Android Fragment 真正的完全解析(上)
- android实体类的Parcelable
- 修改Android Studio的背景颜色
- ELF Hook原理
- Android总结篇系列:Android广播机制
- 今天修改包名时出现 java.lang.ClassNotFoundException: com.myandroid.qqlogin1.MainActivity错误
- Android开发——自动连接指定SSID的wifi热点(不加密/加密)
- 【Android自定义View】测量和绘制浅析
- Android中Looper讲解
- android视图学习---Android深入浅出之Surface[1]
- Android自定义View,贝塞尔曲线
- Elementary0.3.2/Ubuntu14.04安装Android Studio
- 在android 6.0以上无法获取READ_PHONE_STATE权限的SecurityException的问题
- 开发Android微商城记录