一文读懂resource.arsc文件结构

概述

    resource.arsc文件是Apk打包过程中的产生的一个资源索引文件。在对apk进行解压或者使用Android Studio对apk进行分析时便可以看到resource.arsc文件。

    通过学习resource.arsc文件结构,可以帮助我们深入了解apk包体积优化中使用到的 重复资源删除资源文件名混淆 技术。

arsc文件作用

    在java中访问一个文件是需要提供文件的文件名,例如:

    new File("./res/drawable-xxhdpi/img.png");

    然而在Android中,却可以通过drawable Id获得资源文件:

    getDrawable(R.drawable.img);

    这里凭一个id就能获取资源文件内容,省去了文件路径的手动输入,其背后就是通过读取arsc文件实现的。

    这些R.drawable.xxxR.layout.xxxR.string.xxx等的值(存储在R.jar或者R.java文件中)称之为 资源索引 ,通过这些资源索引可以在arsc文件中查取实际的资源路径或资源值;

    例如:
getDrawable(R.drawable.img)在编译后成了getDrawable(2131099964),再将id转为十六进制:

2131099964 = 0x7f06013c

    这时的资源索引为0x7f06013c

    资源索引具有固定的格式:0xPPTTEEEE

PackageId(2位) + TypeId(2位) + EntryId(4位)

  • PP:Package ID,包的命名空间,取值范围为[0x01, 0x7f],第三方应用均为7f。

  • TT:资源类型,有anim、layout、mipmap、string、style等资源类型。

  • EEEE:代表某一类资源在偏移数组中的值

    所以,0x7f06013c中 PackageId = 0x7f、TypeId = 0x06、EntryId = 0x013c

    最简单的我们可以将arsc函数想象成一个含有多个Pair数组的文件,且每个资源类型(TypeId)对应一个Pair[](或多个,为了便于理解先只认为是一个)。因此在arsc中查找0x7f06013c元素的值,就是去设法找到TypeId=0x06所对应的数组,然后找到其中的第0X013c号元素。这个元素恰好就是"img => ./res/drawable-xxhdpi/img.png",左边是资源名称,右边是资源的文件路径,有了这个字符串程序便可以访问到对应的资源文件了。

    当然实际的arsc文件在结构上要稍微复杂一点,下面开始分析arsc文件结构。

chunk

    为了便于理解,在正式介绍resource.arsc(以下简称arsc)文件前,需要对chunk进行解释一下,在其他文章中也多次使用了“chunk”这个词。

    chunk翻译为中文就是“块、部分(尤指大部分,一大块)”的意思,例如:一棵树,可以分为三个chunk(部分):树冠、树茎、树根。也可以将一棵树视为一个chunk,这个chunk就是这棵树。

arsc文件结构

    resources.arsc是一个二进制文件,其内部结构的定义在ResourceTypes.h,不喜欢这个文件的同学,可以先看这张描述arsc文件结构的网络图片。

    图片整体描述了arsc文件中各个chunk的关系(注意结合图片左右两侧内容):

  1. 整个arsc文件是一个 RES_TABLE_TYPE 类型的chunk
  2. RES_TABLE_TYPE 可分为三个部分:文件头部和两个子chunk( RES_STRING_POOL_TYPERES_TABLE_PACKAGE_TYPE );
  3. RES_TABLE_PACKAGE_TYPE 中包含了:头部、资源类型字符串常量池、资源项名称字符串常量池、多个子chunk(RES_TABLE_TYPE_SPEC_TYPERES_TABLE_TYPE_TYPE );
  4. 每种类型的chunk都含有一个头结构

    arsc文件的结构大致可以用如下的伪代码表示:

//---------------------------------------------------------------------------
//: arsc文件是一个 RES_TABLE_TYPE 类型的chunk
RES_TABLE_TYPE {
    table_header//文件头部
    RES_STRING_POOL_TYPE //常量池chunk
    RES_TABLE_PACKAGE_TYPE//内容chunk
}
//---------------------------------------------------------------------------
//:字符串常量池chunk
RES_STRING_POOL_TYPE {
    pool_header//字符串常量池头部
    string[] //常量池
}
//---------------------------------------------------------------------------
//: 内容chunk
RES_TABLE_PACKAGE_TYPE {
    package_header//chunk头部
    RES_STRING_POOL_TYPE//资源类型字符串常量池,类型为:RES_STRING_POOL_TYPE,内容为:[anim,attr,bool,color,dimen,drawable,id,integer,interpolator,layout,mipmap,string,style]
    RES_STRING_POOL_TYPE//资源项名称字符串常量池
    //资源类型chunk:在上述的ResTypeName_StringPool(资源类型常量池)中的每一个类型都有一个资源类型的chunk。这里以drawable为例
    //drawable资源类型chunk
    RES_TABLE_TYPE_SPEC_TYPE{
        spec_header//spec头部
        //drawable-mdpi
        RES_TABLE_TYPE_TYPE
        //drawable-hdpi
        RES_TABLE_TYPE_TYPE
        ...
    }
    //attr资源类型chunk
    RES_TABLE_TYPE_SPEC_TYPE{
        RES_TABLE_TYPE_TYPE
        RES_TABLE_TYPE_TYPE{
            type_header//type头部
            //具体的资源项池:资源名:资源值
            ResName:ResValue
            ResName:ResValue
            ResName:ResValue
            ResName:ResTableMapEntry->[Res_value1, Res_value2]
            ResName:ResTableMapEntry->->[Res_value1, Res_value2,Res_value3]
        }
        ...
    }
    ...
    ...
}
//---------------------------------------------------------------------------

Chunk头结构

    上述说到每一种chunk均由一个头结构开始,在ResourceTypes.h中,这个头结构被定义为ResChunk_header

/**
 * Header that appears at the front of every data chunk in a resource.
 */
struct ResChunk_header
{
   
	
    // Type identifier for this chunk.  The meaning of this value depends
    // on the containing chunk.
    uint16_t type;

    // Size of the chunk header (in bytes).  Adding this value to
    // the address of the chunk allows 
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值