【Rust NDK】热修复?我用Rust实现一下

引言

前面几篇文章各位应该对 jni-rs 的了解比较清晰了。实际上在开发中,除去Rust所有权生命周期 的折磨,大致的用法与C/C++写起来基本一致,而Rust的优势在我看来就是它的各类依赖都统一的放在 crates.io ,简单来说就是比较好找吧。

开发环境

操作系统:Windows 11

编码软件:Visual Studio Code 1.93.1 | Android Studio Ladybug | 2024.2.1 Beta 1

正文

本文将通过 jni-rs 与 Java 的深度结合,来在Rust层实现一个简单的Android热修复案例。

思路整理

首先呢,对于Android的热修复,通常都是通过 DexClassloader 去加载远程下放的 dex 文件,那当然了 InMemoryDexClassLoader 也是 api 28 之后常用的方式了。

本文就基于 DexClassloader的思路来实现一个简单的热修复so库。

熟悉热修复的各位都知道,当我们拿到热修复的 dex文件后,会将它的路径放到 DexPathListElement[] 数组的首位。

然后根据 Classloader 双亲委托的加载机制,当某个类被加载后,就会直接返回该类。而不会继续向后查找,这也就是为何要将热修复 dex 放在 Element[] 数组首位的原因。

创建Rust项目

还是老样子,我们创建名为 example_4 的Rust lib项目,然后通过 vscode 打开它。

接着,按照前几篇文章的步骤,改造这个项目。

开始创建初始化方法。

如上图,我们创建了一个 Java_com_hotfix_HotFix_init 的导出方法,它接收了两个参数 contextdex_path 分别对应 Android 中的 Context 上下文和自定义的热修复文件路径。

然后,通过第9行的红框代码,我们创建了一个mod名为 dex_installer 顾名思义就是对dex进行安装。

接着,第20行代码,我们拿到dex_path变量的Rust String类型的表示,并再次通过对dex_path的定义进行了变量遮掩。

最终,我们调用了dex_installer::install_dex自定的mod和自定义 install_dex 函数对dex进行热修复的安装。

实现install_dex函数

我们切换到定义好的dex_installmod下,进行函数逻辑的实现。

先写一段最基本的逻辑。

到这之后,我们创建好了新的 DexClassloadr 并且将 dex_path 的路径放了进去。

接下来就需要我们拿到 新创建的dex_class_loader原先Context的class_loaderDexPathList

因为两个 classloader 都需要拿到 DexPathList 这里就写一个函数 get_path_list

然后就是拿到 DexPathListElement[] 数组,再次封装成一个函数 get_dex_elements

我们再抽一下共用逻辑,得到最终的实现。

然后,补齐我们前面的 //to do,分别调用 get_path_listget_dex_elements 拿到两个 classloaderDexPathListelement[] 数组,如下图。

接下来呢,就需要对两个数组进行合并,并且对原来的 DexPathList 设置为合并后的 element[] 新值。

因此,我们还需要一个函数 combine_element_array 来对两个 element[] 数组进行合并。

最后,就可以补齐剩下的//to do了。

完整的 install_dex 函数实现,截图如下。

至此,一个简单的热修复实现就完成了。

编译为so库

最后,执行命令行代码,进行so的编译,得到 jniLibs 文件夹。

bash 复制代码
cargo ndk -t armeabi-v7a -t arm64-v8a -o ./jniLibs build --release

创建Android项目

接下来,我们创建一个Android项目并导入jniLibs测试一下。

创建hot子module

我们首先创建一个hot子module。

通过 Build->Rebuild Project 进行项目构建得到aar。

然后,通过压缩工具将这个arr文件中的 classes.jar 解压出来,我这里直接放到桌面上了。

最后通过 d8 命令行工具,将这个 jar 转为 dex 留作备用。

bash 复制代码
d8 --output=output_dex.jar input.jar

这时候再通过压缩工具打开classes_dex.jar就能得到dex文件了。

做完这一切后,我们的热修复dex总算是创建好了。

接下来,开始使用它。

创建好 jni 接口类和方法后,我们需要为 App 创建一个自定义的 Application,并复写它的 attachBaseContext 方法。

我们在app的外部私有目录下创建一个hotfix子目录,内部放入hotfix.dex(也就是刚才d8出来的dex文件,将它改名为hotfix.dex即可)。

这个就是需要被热修复的dex文件了。

接下来,最重要的一步来了。

只读引入hot子module

打开app的build.gradle.kts,将刚才创建的 hot module 进行只读引入。

然后在 MainActivity 中使用它。

最后,Run一下。

热修复

结果自然就可想而知了,肯定是崩溃的下场,因为这个类无法被找到。

那么我们将刚才的dex改名为 hotfix.dex 后推入设备上的指定目录中,让它能够被热修复加载。

之后,再次打开app。

就能够看见修复后的调用结果了。

文章至此,相信各位将这个例子敲下之后(加粗),就已经能够尝试在自己的项目中通过Rust来编写NDK的实现了。

那么,本篇完。

相关推荐
Y多了个想法36 分钟前
RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526
android·rk3568·触摸屏·tp·敦泰·focaltech·ft5526
NotesChapter2 小时前
Android吸顶效果,并有着ViewPager左右切换
android
_祝你今天愉快3 小时前
分析android :The binary version of its metadata is 1.8.0, expected version is 1.5.
android
暮志未晚Webgl3 小时前
109. UE5 GAS RPG 实现检查点的存档功能
android·java·ue5
麦田里的守望者江3 小时前
KMP 中的 expect 和 actual 声明
android·ios·kotlin
Dnelic-4 小时前
解决 Android 单元测试 No tests found for given includes:
android·junit·单元测试·问题记录·自学笔记
佛系小嘟嘟4 小时前
Android Studio不显示需要的tag日志解决办法《All logs entries are hidden by the filter》
android·ide·android studio
mariokkm4 小时前
Django一分钟:django中收集关联对象关联数据的方法
android·django·sqlite
长亭外的少年5 小时前
如何查看 Android 项目的依赖结构树
android
深海呐7 小时前
Android 从本地选择视频,用APP播放或进行其他处理
android·音视频·从本地选择视频,用app播放·从本地选择视频,并拿到信息·跳转到本地视频列表