安卓热修系列-插件资源冲突解决方案

news2024/9/19 21:17:18

作者:37手游移动客户端团队

背景

在做插件化过程中,宿主需要用到插件的资源,涉及到加载插件的资源;

因为插件是以apk的方式存在的,所以插件的ID和宿主的ID可能导致重复;

为了解决这个问题,需要把插件的资源ID重新排一遍,才给宿主加载和使用。

资源加载

Android项目中的资源常规是通过R文件来索引的。打包的时候aapt将工程中的资源名与id在R文件中映射起来。使用资源时是通过Resources获取的,如:

resources.getDrawable(xxxid)

那么怎么加载插件中的资源呢?先看Resources的构造方法:

public Resources(AssetManager assetManager, DisplayMetrics metrics, Configuration config) {
}

Resources的初始化依赖:AssetManager,DisplayMetrics和Configuration。

在AssetManager中有一个方法

public int addAssetPath(String path)

该方法可用于AssetManager增加外部资源,但是AssetManager中该方法不对外公开,需要反射调用,代码大概如下:

val method = AssetManager::class.java.getDeclaredMethod("addAssetPath", String::class.java)
method.isAccessible = true
method.invoke(hostAssetManager, apk)

资源冲突方案

经过上述的处理后,插件的资源和宿主的资源是混合再一起的,因为所有的资源索引不做处理时都是以0x7faabbbb格式按顺序生成的。所以会存在插件资源ID和宿主资源ID冲突的情况(注意:资源索引共四个字节32位,第一个字节代表PackgeID,第二个字节代表TypeID,后两个字节代表资源值)

怎么解决冲突呢?有几种方案:

方案一:资源隔离

资源隔离就是宿主和插件使用不同的Resources对象,这样使用的资源文件不同,不存在冲突。代码调整如下:

//通过反射生成一个新的AssetManager实例
val am = AssetManager.class.newInstance()
//添加资源
val method = AssetManager::class.java.getDeclaredMethod("addAssetPath", String::class.java)
method.isAccessible = true
method.invoke(am, apk)
//生成新的Resources对象
val pluginResources = Resources(am, hostResources.displayMetrics, hostResources.configuration)

插件使用这个PluginResources。但是这里会有一些缺点:

1、宿主和插件的资源无法共享,使用起来不太方便

2、PluginResouces中不包含系统资源,在某些用到系统资源的场景会报错。如:加载前端页面,使用select标签时会使用到系统的一些资源

3、某些业务场景下,插件的Resources和宿主的Resources需要用同一个。如:游戏发行sdk,sdk相关界面非activity,使用到的Resources是游戏研发方activity(在宿主中)。

方案二:修改资源id

修改资源id,当前常用的方案有:

方案1:Android的资源id是aapt生成的,修改aapt,让插件中的资源id不从0x7f开始,比如从0x6f开始

方案2:生成插件apk后,修改插件apk中resources.arsc文件。resources.arsc文件是有固定格式的文件

可通过解析该文件修改资源索引值。但是存在一定缺陷:

1、修改难度较大,需要了解resources.arsc格式

2、只修改resources.arsc是不够的,因为代码中使用的是R类,还同时需要修改代码中的值;

方案3:通过反编译修改插件中的public.xml文件中的索引值,以及修改smali中的R类值

public.xml这个文件是哪来的?

该文件是apktool在反编译apk时,根据apk包中的resources.arsc文件生成。 没看过resource.arsc? (自己拖个apk到IDE看吧)

public.xml有什么作用

publc.xml是aapt在打包资源时用来固定资源id的,如果资源在public.xml中有对应的id了,那么打包资源时就用已经有的id。

public.xml中的id的格式

共四个字节32位,第一个字节代表PackgeID,第二个字节代表TypeID,后两个字节代表资源值

通常系统资源PackageID是01,而我们自己的资源PackageID是7f

TypeID,比如attr为01,string为02。但是并不固定,并不一定attr就是01。但是在public.xml中,同类型的该字节一定是一样的,否则回编译会失败。

R类

R类这里有个知识点,library模块中生成的R类中的成员的值不是常量,不带final。app模块生成的R类的值是常量值。而常量值在java编译时会被优化,最终代码中输出的就是常量值,而不是R.id.xxx这样。而library的因为是变量,不会被优化,代码中会保留R.id.xxx

R类和public.xml的关系

从本质上讲,其实并没有啥关系。但是由于在代码中我们会使用R.id去查找资源,这就关联上了。如果都用getIdentifier的方式先获取id,那把R类删了也没事。

public.xml打包后对应的就是resources.arsc中的值,而资源值生成Java类,这个类就是R类。也就是说平时使用R类,就是用里面的索引值去到resources.arsc中找到对应资源位置,再去加载。

修改步骤如下:

1、反编译插件apk

2、修改public.xml,将0x7faabbbb中的aa的值调高,比如0x7f010001→0x7f510001,因为第二个字节是TypeID,是按顺序增加的,而这个type实际上是没有多少的。修改成比较大的值后就不会冲突了。 (具体修改可参考提供代码中的PublicXmlBean类实现)

3、修改R$x.smali的值,反编译后R类就是一些smali代码,扫描smali代码,将其中的值也都按同样的规则增大。这样R类和resources.arsc依旧是对应的,代码中的R类正常。但是这里需要注意的是application模块的R类由于是final常量值,会被处理成常量。这种情况下修改R类其实不会有作用。而library的情况则可以。因此需要将涉及到R的代码及资源文件下沉为library模块依赖。

4、回编译,得到修改资源索引后的插件

源码工程简介

概要

程序入口

插件生成小tips

插件源码工程中的插件apk结构(也就是plugin.apk):

实际代码下沉为resmodule作为library模块,app模块中并无实际功能,仅仅作为application模块引用library,这样就可以输出我们的插件plugin.apk。 这样做的目的上面有说,其实就是避免我们的代码等在app模块,被弄成常量了。

效果

用工具修改前的R.layout.activity_main的值为2131296284,转换为16进制为0x7f09001c

用工具修改后再次查看R.layout.activity_main的值为2136539164,即0x7f59001c

总结

本文介绍了插件资源加载的多种方案,可以按照自己的使用场景以及团队技术能力选择合适的方案

Android 学习笔录

Android 性能优化篇:https://qr18.cn/FVlo89
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/705229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[游戏开发][Unity]点击Play按钮卡顿特别久

一般小工程不会遇到这个问题,我在公司接手了几个老项目,都遇到了这个问题。每次Play卡顿几分钟甚至十几分钟,很是头疼。

DL学习11-nin-mnist

对于使用卷积神经网络加全连接层的结构而言,对于全连接的参数的巨大了,对于简单的任务容易造成过拟合,且会增加模型的额外开销,例如alexnet,vgg等,全连接层的开销会随着参数的增加而爆炸式增长。 nin旨在使…

ELK增量同步数据【MySql->ES】

一、前置条件 1. linux,已经搭建好的logstasheskibana【系列版本7.0X】,es 的plugs中安装ik分词器 ES版本: Logstash版本: (以上部署,都是运维同事搞的,我不会部署,同事给力&#…

动态SLAM论文(3) — Detect-SLAM: Making Object Detection and SLAM Mutually Beneficial

目录 1 Introduction 2 Related Work 3 Detect-SLAM 3.1 移动物体去除 3.2 Mapping Objects 3.3 增强SLAM检测器 4 实验 4.1 动态环境下的鲁棒SLAM 4.2. 提升检测性能 5 结论 Abstract:近年来,在SLAM和目标检测方面取得了显著进展,…

使用python sdk添加删除阿里云pvc路由

1. 前言 由于线路供应商sdwan存在单点问题,需要实现线路高可用解决方案,需要设计自动切换阿里云vpc路由解决方案。通过阿里云文档了解,可通过阿里云专有网络Python SDK,通过sdk实现创建、删除、查询等vpc网络相关操作&#xff08…

如何与德科斯米尔Draexlmaier 建立 EDI 连接?

德科斯米尔Draexlmaier(以下简称为DRX)是一家总部位于德国的汽车零部件供应商和系统集成商,如今已成为全球领先的汽车内部装饰系统、电气和电子系统、电缆技术以及储能系统的制造商之一。EDI 帮助DRX与其交易伙伴之间实现信息流的一致性、无误…

CHATGPT使用笔记

CHATGPT是帮你做事,而不是替你做事 1、联网插件: 使用Webpilot插件联网时还可以同时使用其它两种插件(一次可以同时使用三个插件),而使用Web Browsing插件功能联网时无法使用插件功能(联网功能和插件只能…

SpringBoot2+Vue2实战(八)文件上传实现

一、文件上传 创建数据库表 Files import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data;Data TableName("sys_file") public cl…

18.RocketMQ中消息重复的场景和幂等处理

highlight: arduino-light 消息重复的场景 发送消息异常,重试发送导致消息重复★ 当一条消息已被成功发送到服务端并完成持久化。此时出现网络闪断或者客户端宕机,导致服务端对生产者的确认应答失败。生产者发送消息到mq时发送成功未获取到响应,然后生产者进行消息发…

信号链噪声分析18

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 提示:这里可以添加技术概要 到目前为止,我们考虑的是基带采样情况,即所有目标信号均位于第一奈奎斯特区内。 图 显示了另外一种情况,其中采样信号频带局限于第一奈奎斯…

5.8.1 TCP概述

5.8.1 TCP概述 TCP是在Internet中TCP/IP协议家族中最为重要的协议之一,因特网中各种网络特性参差不齐,所以必须要有一个功能很强的互联网可靠传输协议的要求,TCP特点要与UDP特点对比来看。 UDP特点TCP特点无连接面向连接不可靠的服务可靠的…

一文详解!自动化测试如何管理测试数据

目录 前言 脚本与数据捆绑 配置文件 测试文件 数据库管理 数据平台 综述 前言 测试数据管理是自动化测试中非常重要的一环,它涉及到数据的创建、存储、维护和管理。 在之前的自动化测试框架相关文章中,无论是接口自动化还是UI自动化&#xff0c…

机器学习-支持向量机SVM

文章目录 前言1 支持向量机1.1 数据集示例11.2 带有高斯核的SVM1.2.1 高斯核1.2.2 数据集示例21.2.3 数据集示例3 2 垃圾邮件分类2.1 邮件预处理2.2 训练SVM进行垃圾邮件分类 前言 在本练习中,我们将使用支持向量机(SVM)来构建垃圾邮件分类器…

机器学习基础之《概述》

一、机器学习与人工智能、深度学习 1、机器学习是人工智能的一个实现途径 2、深度学习是机器学习的一个方法发展而来 二、统计学习和机器学习 实际机器学习在上世纪80年代已经出现,搞统计的 机器学习中有一个方法,叫人工神经网络,发展成深度…

高压线路距离保护程序逻辑原理(六)

(三)振荡与短路故障的区分 在系统发生振荡时,又发生短路故障的机率虽然不多,但万一发生应要求保护能可靠地动作于跳闸。这就要求保护能很好地区分振荡和短路故障。但是在常规距离保护中,对振荡闭锁后再发生故…

【机器学习】比较全面的XGBoost算法讲解

本文是《机器学习入门基础》(黄海广著)的第十章的部分内容。 XGBoost算法 XGBoost是2014年2月由华盛顿大学的博士生陈天奇发明的基于梯度提升算法(GBDT)的机器学习算法,其算法不但具有优良的学习效果,而且训练速度高效&#xff0c…

【软件测试】测试的分类

目录 测试的分类 1.按测试对像划分 ⭐1.界面测试 2.可靠性测试 3.容错性测试 4.文档测试 ⭐5.兼容性测试: ⭐6.易用性测试: ⭐7.安装卸载测试 ⭐8. 安全测试: ⭐9.性能测试 10.内存泄漏测试 2.按是否查看代码划分 1.黑盒测试(…

Html + Jquery + Vue前端学习笔记

文章目录 一,Vue1,v-model 数据绑定2,生成描述列表 二,HtmlJquery1,动态修改类名2,layui手风琴效果3,输入框样式修改4,多行文本显示省略号5,div内容居右6,字符…

Mysql基础教程

SELECT Company FROM Orders SQL 简介 SQL 教程SQL 语法 SQL 是用于访问和处理数据库的标准的计算机语言。 什么是 SQL? SQL 指结构化查询语言SQL 使我们有能力访问数据库SQL 是一种 ANSI 的标准计算机语言 编者注:ANSI,美国国家标准化…

HDFS之Java客户端操作

HDFS之Java客户端操作 文章目录 HDFS之Java客户端操作写在前面准备Windows关于Hadoop的开发环境下载依赖配置HADOOP_HOME环境变量配置Path环境变量 创建Maven工程XML文件创建新的Package创建HdfsClient类执行程序 HDFS的API操作 写在前面 Hadoop版本:Hadoop-3.1.3L…