【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的实现了。

那么,本篇完。

相关推荐
猿~阿峰36 分钟前
MySQL
android·mysql·adb
我命由我123453 小时前
7-1.Android SQLite 之 SQLiteDatabase 简单编码模板(SQLiteDatabase 使用、SQL 语句编写)
android·数据库·sql·sqlite·安卓·database·android-studio
火红的小辣椒5 小时前
PHP反序列化5(回调函数call_user_func_array)
android·开发语言·php
西瓜本瓜@5 小时前
最新的iOS 18版本和Android 15版本系统分别升级了哪些功能?
android·ios
limingade6 小时前
手机实时提取SIM卡打电话的信令声音-(题外、插播一条广告)
android·物联网·计算机外设·音视频·webrtc·信号处理
彭于晏6896 小时前
Activity
android·java·android-studio
Reese_Cool8 小时前
【数据结构与算法】算法和算法分析
android·c语言·数据结构·算法
咸芝麻鱼10 小时前
Android Studio中导入了包,但无法识别 WindowSizeClass 和相关函数的问题
android·ide·android studio
佛系小嘟嘟10 小时前
Android Studio 新版本 Logcat 的使用详解
android·gitee·android studio