美文网首页
Android资源管理器过程分析 & 插件化实现Hook 资源管

Android资源管理器过程分析 & 插件化实现Hook 资源管

作者: AntCoding | 来源:发表于2019-03-10 12:51 被阅读0次

简 录

概括[1]

资源分类
资源打包

自定义资源ID的取值范围[2]

使用场景
自定义方式

Android资源管理器AssetManager的创建过程[3]

上下文环境解析
多个APK环境下资源的存储方式
AssetsManger和Resources如何实现资源访问的

Android-Framework-Plugin插件化资源创建[4]

概括

概括中主要讲解资源的基础认知及资源的打包过程和注意事项

资源分类

  • assets资源
  • res资源 > res目录下的资源会被赋予ID.方便我们通过ID访问资源
  • animator -> 属性动画
  • anim ->补间动画
  • color ->颜色资源
  • drawable -> 图片资源
  • layout -> 布局资源
  • menu ->菜单资源
  • raw ->任意格式资源,它同assets下资源一样会原封不动的打入APK文件中,不过它仍会被赋予ID,我们也可以通过ID访问它

Resources res = getResources();
InputStream is = res .openRawResource(R.raw.filename);

  • values ->描述一些简单资源
  • xml ->描述应用程序的配置信息资源
注意:
  • 上述9种类型资源,除了raw类型资源和Bitmap文件的drawable类型资源外,其余的资源都将在打包过程中编译成二进制格式的xml文件,
    这些二进制文件分别有一个字符串资源池,用来保存文件中引用到的资源,
    这样做的好处
  • 文件占用更小
  • 解析速度更快
  • Res资源在编译完成后都会分配一个资源ID,会被保存到 R.java文件中与应用程序的其他源文件一起编译到程序中 ID唯一性,不唯一则出现资源冲突

资源打包过程

  • 除了assets和res/raw资源被原封不动打进APK之外,其他资源会被编译成二进制文件打进APK
  • 除了assets资源之外,其他资源都会被赋予一个资源ID
  • 打包工具完成对资源的打包和编译后会生成一个 resources.arsc 文件和 R.java 文件,前者是 资源索引表,后者是 资源ID表
  • AndroidManifest.xml同样会被编译成二进制的XML文件
  • 应用程序通过AssetManager来访问资源,或通过资源ID访问,或通过文件名访问

自定义资源ID的取值范围

使用场景

当我们在插件定义的资源打包是编译到宿主资源链表时,为了避免这些资源与宿主的资源冲突,所以需要我们为宿主的资源定义一个ID范围.

自定以资源方式

在Android资源中,有一种资源类型称为Public,他们一般定义在res/values/public.xml文件中,形式如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--在宿主中指定这些id的范围是为了使宿主各类资源的id和插件各类资源的id不重复,否则会出错(若没出错也仅是凑巧)-->
    <!-- 单独指定属性的资源范围是为了支持主题属性换肤  将end值设置为0100,意思预留从0000到0100的id给插件属性使用
        即插件的attr不可超过256个,这个值可以根据实际情况调整
     -->
    <public-padding type="attr" name="public_static_final_host_attr_"     start="0x7f010000" end="0x7f010100" />
    <!-- 除属性外 其他类型的资源设置为  0x7f32开始 -->
    <public-padding type="drawable" name="public_static_final_host_drawable_" start="0x7f320000" end="0x7f320000" />
    <public-padding type="layout" name="public_static_final_host_layout_"   start="0x7f330000" end="0x7f330000" />
    <public-padding type="anim" name="public_static_final_host_anim_"     start="0x7f340000" end="0x7f340000" />
    <public-padding type="xml" name="public_static_final_host_xml_"      start="0x7f350000" end="0x7f350000" />
    <public-padding type="raw" name="public_static_final_host_raw_"      start="0x7f360000" end="0x7f360000" />
    <public-padding type="dimen" name="public_static_final_host_dimen_"    start="0x7f370000" end="0x7f370000" />
    <public-padding type="string" name="public_static_final_host_string_"   start="0x7f380000" end="0x7f380000" />
   <public-padding type="style" name="public_static_final_host_style_"    start="0x7f390000" end="0x7f390000" />
    <public-padding type="color" name="public_static_final_host_color_"    start="0x7f3a0000" end="0x7f3a0000" />
    <public-padding type="id" name="public_static_final_host_id_"       start="0x7f3b0000" end="0x7f3b0000" />
    <public-padding type="bool" name="public_static_final_host_bool_"     start="0x7f3c0000" end="0x7f3c0000" />
    <public-padding type="integer" name="public_static_final_host_int_"  start="0x7f3d0000" end="0x7f3d0000" />
    <public-padding type="array" name="public_static_final_host_array_"    start="0x7f3e0000" end="0x7f3e0000" />
    <public-padding type="menu" name="public_static_final_host_menu_"     start="0x7f3f0000" end="0x7f3f0000" />
    <public-padding type="mipmap" name="public_static_final_host_mipmap_"     start="0x7f400000" end="0x7f400000" />
    <public-padding type="animator" name="public_static_final_host_animator"     start="0x7f410000" end="0x7f410000" />
    <public-padding type="fraction" name="public_static_final_host_fraction"     start="0x7f420000" end="0x7f420000" />
    <public-padding type="font" name="public_static_final_host_font"     start="0x7f430000" end="0x7f430000" />
    <public-padding type="plurals" name="public_static_final_host_plurals"     start="0x7f440000" end="0x7f440000" />
    <public-padding type="interpolator" name="public_static_final_host_interpolator"     start="0x7f450000" end="0x7f450000" />
    <public-padding type="transition" name="public_static_final_host_transition"     start="0x7f460000" end="0x7f460000" />
    <public-padding type="_aapt" name="public_static_final_host__aapt"     start="0x7f470000" end="0x7f470000" />
</resources>
xml分析
  • type 用于指定资源类型
  • name 用于appt在编译时重赋资源的name名称,name_资源名
  • start 取值起始位置
  • end 取值结束位置

每当aapt重新编译被修改过的资源时,都会重新给这些资源赋予ID

Android资源管理器AssetManager的创建过程

上下文环境解析

  • 每个Activity都会关联一个ContextImpl对象,Activity和ContextImpl都继承于Context;
  • 所以Activity大部分成员函数通过都调用ContextImpl对象的对应函数做处理的,其中访问程序资源是通过调用ContextImpl对象的getResources()和getAssets() 函数来实现的
  • getResources()

返回一个Resources对象,通过Resources对象我们就可以通过资源ID访问资源

  • getAssets()

返回一个AssetsManager对象,通过AssetsManager对象我们就可以通过文件名访问被编译过的资源文件

  • 事实上Resources也是通过AssetsManager来访问资源文件的,只不过它会先通过资源ID查找到资源文件名

多个APK环境下资源的存储方式

Android系统允许一个进程中存在多个apk文件,每个APK文件都会有一个全局的Resources对象和AssetsManager对象,

  • 全局的Resources对象存储在对应的ContextImpl对象的成员变量mResources中
  • 全局的AssetsManager对象存储在对应的Resources对象的成员变量mAssets中

AssetsManger和Resources如何实现资源访问的

Resources访问资源
  • Resources类中的成员函数getAssets(),通过getAssets()可以获取Resources类中成员变量mAssets的AssetsManager对象,所以访问资源最终实现仍在AssetsManager实现的
AssetsManager访问资源
  • 1.AssetsManager类除了Java层的实现外,还有C++层对应的实现。而Java层的AssetsManager类的功能就是通过C++层来实现的;
  • 2.Java层每个AssetsManager对象都有一个int类型的成员变量mObject,mObject保存的便是在C++层对应的AssetsManager对象地址.
  • 3.通过mObject这个变量可以将Java层对象和C++层对象关联起来
  • 4.C++层的AssetsManager类有三个重要的成员变量
  • mAssetPaths -> 资源存放目录
  • mResources -> 指向一个资源索引表,以供Resources对象通过资源ID访问资源
  • mConfig -> 设备的本地配置信息,包括屏幕的密度和大小、国家地区、语言等
    有了这三个变量后,C++层的AssetsManager类就可以访问程序资源了
Android-Framework-Plugin插件化资源创建
  • 1.创建一个AssetManager的代理类的实例,因为是对AssetManager做代理,所以需要将AssetManasger的实例传入到代理中
 HackAssetManager hackAssetManager = new HackAssetManager(assetMgr);
  • 2.在HackAssetManager中通过反射将assetPaths数组中的资源路径添加进去
hackAssetManager.addAssetPaths(assetPaths);​
  • 3.完成以上步骤后我们需要创建字符串资源池来实现资源的添加
hackAssetManager.ensureStringBlocks();  //创建字符串资源池

4.现在我们可以获取资源了

​Resources pluginRes = new PluginResourceWrapper(assetMgr, mainRes.getDisplayMetrics(),mainRes.getConfiguration(), pluginDescriptor);
// assetMgr 是我们融合后的Asset资源
​//mainRes 是宿主的Resources实例,调用了其中的两个属性方法
//pluginDescriptor 是插件的​​属性数据序列化类实例​
//通过实例化此得到一个Resources资源实例,​

具体的实现代码请移步Android-Fragmework-Plugin,GitHub地址

This ALL! Thanks EveryBody!


  1. 概括

  2. 自定义资源ID的取值范围

  3. Android资源管理器AssetManager的创建过程

  4. Android-Framework-Plugin插件化资源创建

相关文章

网友评论

      本文标题:Android资源管理器过程分析 & 插件化实现Hook 资源管

      本文链接:https://www.haomeiwen.com/subject/fyjkxqtx.html