引言
前面几篇文章各位应该对 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
文件后,会将它的路径放到 DexPathList
中 Element[]
数组的首位。
然后根据 Classloader
双亲委托的加载机制,当某个类被加载后,就会直接返回该类。而不会继续向后查找,这也就是为何要将热修复 dex
放在 Element[]
数组首位的原因。
创建Rust项目
还是老样子,我们创建名为 example_4
的Rust lib项目,然后通过 vscode 打开它。
接着,按照前几篇文章的步骤,改造这个项目。
开始创建初始化方法。
如上图,我们创建了一个 Java_com_hotfix_HotFix_init
的导出方法,它接收了两个参数 context
和 dex_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_install
mod下,进行函数逻辑的实现。
先写一段最基本的逻辑。
到这之后,我们创建好了新的 DexClassloadr
并且将 dex_path
的路径放了进去。
接下来就需要我们拿到 新创建的dex_class_loader
和 原先Context的class_loader
的 DexPathList
。
因为两个 classloader
都需要拿到 DexPathList
这里就写一个函数 get_path_list
。
然后就是拿到 DexPathList
的 Element[]
数组,再次封装成一个函数 get_dex_elements
。
我们再抽一下共用逻辑,得到最终的实现。
然后,补齐我们前面的 //to do
,分别调用 get_path_list
和 get_dex_elements
拿到两个 classloader
的 DexPathList
和 element[]
数组,如下图。
接下来呢,就需要对两个数组进行合并,并且对原来的 DexPathList
设置为合并后的 element[]
新值。
因此,我们还需要一个函数 combine_element_array
来对两个 element[]
数组进行合并。
最后,就可以补齐剩下的//to do
了。
完整的 install_dex
函数实现,截图如下。
至此,一个简单的热修复实现就完成了。
编译为so库
最后,执行命令行代码,进行so的编译,得到 jniLibs
文件夹。
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 留作备用。
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的实现了。
那么,本篇完。
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/22288,转载请注明出处。
评论0