【问题标题】:Android compiled resources - resources.arscAndroid编译资源——resources.arsc
【发布时间】:2014-12-18 14:27:06
【问题描述】:

我试图弄清楚“编译资源”是什么意思。

为了理解这个问题我做了什么:

我已经阅读了很多关于这个主题的文章,但没有找到一个简单的答案。 我读过的最好的一篇是:How does the mapping between android resources and resources ID work?

我是怎么理解的:

据我了解,当我们通过 ANT (Eclipse) 或 Gradle (AS) 编译项目时。 我们使用一个名为 aapt 的工具 - Android 资产打包工具,它: 用于为我们的每个资源生成唯一 ID,例如我们的布局、我们的样式等,并将它们存储在查找表中。然后它通过生成两个文件来持久化这个查找表:

  1. 它生成具有这些唯一 ID 的 R.java 文件,因此我们将能够在编译期间使用我们的 java 代码中的资源。
  2. 它生成resources.arsc 文件,可以在resources*.ap_ 文件中找到。 这个resources.arsc文件稍后会被apktool打包到apk中。
    这种arsc文件格式是一种在运行时很容易被设备映射和解析的格式。

一个例子:

为了简单起见:假设我的activity_main.xml中有这个:

    <TextView android:id="@+id/my_textView"
        android:text="@string/hello_world" 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

我从我的 onCreate 中调用它:

findViewById(R.id.my_textView)

在我的 R.java 文件中我会看到:

public static final int my_textView=0x7f08003f;

Using: aapt dump resources on the generated apk 我可以看到它包含两行 my_textView: ec 资源 0x7f08003f com.example.lizi.liortest2:id/my_textView: flags=0x00000000 资源 0x7f08003f com.example.lizi.liortest2:id/my_textView: t=0x12 d=0x00000000 (s=0x0008 r=0x00)

我不明白的地方:

我原以为这个 resources.arsc 文件不仅包含资源 ID,还包含我为视图定义的所有属性,例如 android:layout_width="wrap_content"。

所以现在在运行时 VM 尝试运行 findViewById(R.id.my_textView) 它如何知道要获取哪个视图/要创建它的属性?

我简直无法理解它是如何工作的……这个查找表不应该也包含属性数据吗? 这个 0x7f08003f 数字是什么? (它应该代表一个稍后将映射到存储对象的物理内存的值吗?)

【问题讨论】:

    标签: android resources r.java-file


    【解决方案1】:

    TL;DR:在 android 资产包工具 (aapt) 的帮助下,xml 节点被转换为 Java 类,相应的 xml 属性被转换为数字 Id。 Android 运行时使用这些数字 id 来实例化类并创建视图

    TL;R

    运行此命令转储二进制 xml
    aapt d xmltree apk_file_name res/layout/activity_main.xml(aapt 可以在 android-sdk-dir/build-tools/23.0.2/aapt.exe 中找到 )

    这将显示 xml 节点(例如 LinearLayoutRelativeLayout 等)及其属性(例如 android:layout_width, android:layout_height)及其值。请注意,在那里可以看到常量match_parent(数值0xffffffff-1)或wrap_content(数值0xfffffffe-2)。

    事实上,您可以在 apk 中的任何其他 xml 文件上使用此命令,例如AndroidManifest.xml or other layout files

    apk 文件只是一个 zip 压缩包,其中包含所有 java 类文件 (classes.dex)、所有已编译的资源文件和一个名为 resources.arsc 的文件。 这个resource.arsc 文件包含有关资源的所有元信息。其中一些是...

    • xml 节点(例如LinearLayoutRelativeLayout 等),
    • 属性(例如android:layout_width),
    • 资源id的。

    资源id 指的是apk 文件中的真实资源。属性在运行时被解析为一个值。解析过程对任何重定向都很智能(@dimen/...4dp@color/... 相比 "#FFaabbcc")并返回可用值(dimen 值的解析方式不同于 color值)。

    什么是已编译的 XML 文件: 已编译的 XML 文件与将资源引用更改为相应的 ids 的 XML 文件相同。例如,引用 @string/ok 将替换为 0x7f000001。此外,android 命名空间中的属性更改为各自的整数值(例如,wrap_content 更改为0xfffffffe-2

    Android 如何在运行时解析资源: 方法inflater.inflate() 解析已编译的xml 文件并通过实例化xml 节点来创建视图层次结构。每个 xml 节点都由一个 java 类(例如 LinearLayout.java、RelativeLayout.java)实例化。为了实例化,inflater 解析编译的 xml 文件,收集节点的所有属性和creates 类型为AttributeSet 的打包结构。这个AttributeSet 被传递给类构造函数。类构造函数负责遍历AttributeSet 并解析每个属性值。

    例如,对于包含RelativeLayout 的布局,inflater 会将layout_widthlayout_height 打包成AttributeSet 并将其传递给构造函数

    RelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes).

    在这种情况下,某些属性由RelativeLayout.initFromAttributes() 解析。其余属性由父 ViewGroup.initFromAttributes() 解析。视图的属性android:id 只是另一个属性。在inflating之后,inflater通过calling setId(id)将每个view的id存储在实例化后的那个view上

    现在回答您的问题 R.id 是一个 java 数组,R.id.my_textview 是该数组中的一个整数。视图my_textviewid 就是这个整数(以0x7f 开头)。 findViewById() 方法在该视图层次结构上进行深度优先搜索以找到相应的视图。

    希望这会有所帮助。您在问题中提供的link 已经回答了 aapt 如何生成 id。

    它是一个出色的系统,用于管理具有多维度变化的设备的资源。而且,执行速度真的很快!!以此为基础,它允许实现更高级别的功能(例如Runtime Resource Overlay

    【讨论】:

    • 多么棒的答案。你是安卓吗?
    • 谢谢!如何提取字符串? strings.xml 不存在(以及 values 文件夹)。我知道,二进制resources.arsc 文件中存在一个搜索字符串,但我无法从那里提取它。破解者可以从那里提取任何资源(字符串、数组、颜色)吗?
    【解决方案2】:

    LayoutInflater 使用 XML 字符串扩展视图。如您在问题中提到的,将 XML 字符串编译到资源文件中。

    请检查AOSP的这些代码sn-ps:

    public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
        final Resources res = getContext().getResources();
        if (DEBUG) {
            Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                    + Integer.toHexString(resource) + ")");
        }
    
        final XmlResourceParser parser = res.getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }
    

    Resources.getLayout 加载 XML 资源解析器

    public XmlResourceParser getLayout(int id) throws NotFoundException {
        return loadXmlResourceParser(id, "layout");
    }
    
    XmlResourceParser loadXmlResourceParser(int id, String type)
            throws NotFoundException {
        synchronized (mAccessLock) {
            TypedValue value = mTmpValue;
            if (value == null) {
                mTmpValue = value = new TypedValue();
            }
            getValue(id, value, true);
            if (value.type == TypedValue.TYPE_STRING) {
                return loadXmlResourceParser(value.string.toString(), id,
                        value.assetCookie, type);
            }
            throw new NotFoundException(
                    "Resource ID #0x" + Integer.toHexString(id) + " type #0x"
                    + Integer.toHexString(value.type) + " is not valid");
        }
    }
    

    getValue 使用AssetManagergetResourceValue 并调用loadResourceValue 本地方法。此原生方法调用ResTablegetResource 方法来获取存储在资源文件中的XML 字符串。

    【讨论】:

      【解决方案3】:
      Use appt for android-sdk (ex:- /build-tools/27.0.3/aapt )
      
       run given script and get resources.arsc file content
      ./aapt dump resources ./debug.apk
      
      Package Groups (1)
      Package Group 0 id=0x7f packageCount=1 name=com.dianping.example.activity
        Package 0 id=0x7f name=com.dianping.example.activity
          type 1 configCount=3 entryCount=1
            spec resource 0x7f020000 com.example.activity:drawable/ic_launcher: flags=0x00000100
            config mdpi-v4:
              resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000000 (s=0x0008 r=0x00)
            config hdpi-v4:
              resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000001 (s=0x0008 r=0x00)
            config xhdpi-v4:
              resource 0x7f020000 com.example.activity:drawable/ic_launcher: t=0x03 d=0x00000002 (s=0x0008 r=0x00)
          type 2 configCount=1 entryCount=1
            spec resource 0x7f030000 com.dianping.example.activity:string/app_name: flags=0x00000000
            config (default):
              resource 0x7f030000 com.dianping.example.activity:string/app_name: t=0x03 d=0x00000003 (s=0x0008 r=0x00)
      

      这个链接可能对http://elinux.org/Android_aapt有帮助

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-02
        相关资源
        最近更新 更多