使用Javassist 在android运行时生成类

序言

最近在写框架,有一个需求就是动态的生成一个类,然后查阅了相关文献,发现在android中动态生成一个类还挺麻烦。因次把一些内容分享出来,帮助大家少走弯路。

方案一 DexMaker

DexMaker 是一个针对 Android 平台的库,用于在运行时生成 Dalvik 字节码。Dalvik 字节码是 Android 应用程序的底层运行代码,而 DexMaker 允许开发人员在运行时动态地创建和修改这些代码。这对于某些类型的测试和动态代码生成非常有用,例如在单元测试中模拟对象或者生成代理类。 DexMaker 主要用于测试框架和其他需要在运行时生成代码的库中。

dexmaker源码

dexmaker

引入dexmaker

testCompile "com.crittercism.dexmaker:dexmaker:1.4"
testCompile "com.crittercism.dexmaker:dexmaker-dx:1.4"
testCompile "com.crittercism.dexmaker:dexmaker-mockito:1.4"

缺点

我最开始也是准备用这个库的,但是这个库是基于字节码的,要模拟虚拟机的运行。有点像是在写汇编语言,对使用者来说不是很优化。而且相关的资料也不多。所以准备找一个更友好的库。

方案二 Javassist

Javassist(Java Programming Assistant)是一个用于在运行时编辑字节码的 Java 库。它允许开发人员在运行时创建、编辑和修改 Java 类的字节码,从而实现动态生成类、动态修改类以及实现各种 AOP(面向切面编程)等功能。

Javassist 提供了简单易用的 API,使开发人员能够以编程方式操作字节码,而不必直接操作底层的字节码指令。通过 Javassist,开发人员可以在运行时动态地创建新的类、修改现有类的结构、添加、修改或删除类的字段和方法等。

Javassist 在许多领域都有广泛的应用,包括动态代理、AOP、ORM(对象关系映射)、代码生成等。它被广泛应用于 Java EE、Android 开发以及许多其他 Java 相关的项目中。

最关键的是API更友好,资料更多。

在这里插入图片描述

面临的问题

这个库很好用,但是基于的是java的字节码。而android运行的是dex字节码。所以需要在运行时,将java字节码,编译为dex文件,再加载dex文件,加载最后的类。翻遍github只找到了这个库,代码已经是12年前的了。而且已经不再维护了。

在这里插入图片描述

运行起来

经过我的不断的改造,终于把源文件改造为gralde形式,可以运行起来了。而且支持android 30。

测试代码

public class MainActivity extends Activity {private static final String DEX_FILE_NAME_MYCLASSES = "myclasses.dex";private static final boolean FORCE_GENRATE_DEX = false;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);final TextView view = (TextView)findViewById(R.id.textview_title);final File dexFile = new File(getFilesDir(), DEX_FILE_NAME_MYCLASSES);if (!dexFile.exists() || FORCE_GENRATE_DEX) {// generate DEX and ODEX file.try {// generate "xxx.class" file via Javassist.final ClassPool cp = ClassPool.getDefault(getApplicationContext());final CtClass cls = cp.makeClass("hoge");final CtConstructor ctor = new CtConstructor(null, cls);ctor.setBody("{}");cls.addConstructor(ctor);final CtMethod m1 = CtMethod.make("public java.lang.String toString() { return \"hoge.toString() is called.\"; }",cls);cls.addMethod(m1);final CtMethod m2 = CtMethod.make("public void setText(android.widget.TextView view) { view.setText((java.lang.CharSequence)\"hoge.setText() is called 222.\"); }",cls);// 创建注解AnnotationsAttribute attr = new AnnotationsAttribute(m2.getMethodInfo().getConstPool(), AnnotationsAttribute.visibleTag);Annotation annotation = new Annotation("android.annotation.TargetApi", m2.getMethodInfo().getConstPool());attr.addAnnotation(annotation);// 在方法上添加注解m2.getMethodInfo().addAttribute(attr);cls.addMethod(m2);cls.writeFile(getFilesDir().getAbsolutePath());// convert from "xxx.class" to "xxx.dex"final DexFile df = new DexFile();final String dexFilePath = dexFile.getAbsolutePath();df.addClass(new File(getFilesDir(), "hoge.class"));df.writeFile(dexFilePath);} catch (Exception e) {e.printStackTrace();Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();}}if (dexFile.exists()) {try {final DexClassLoader dcl = new DexClassLoader(dexFile.getAbsolutePath(),getCacheDir().getAbsolutePath(),getApplicationInfo().nativeLibraryDir,getClassLoader());String title = null;final Class<?> class_hoge = dcl.loadClass("hoge");final Constructor<?> ctor = class_hoge.getConstructor(new Class<?>[0]);final Object obj = ctor.newInstance(new Object[0]);title = obj.toString();view.setText(title);new Handler().postDelayed(new Runnable() {@Overridepublic void run() {try {final Method m = obj.getClass().getDeclaredMethod("setText", TextView.class);m.invoke(obj, view);} catch (Exception e) {e.printStackTrace();Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();}}}, 2000);} catch (Exception e) {e.printStackTrace();Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();}}}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.activity_main, menu);return true;}
}

生成的dex

在这里插入图片描述

反编译查看结果

在这里插入图片描述
推荐上面的反编译工具,可以直接把dex反编译为源文件,使用也很简单,拖进去就行了

jadx

运行结果

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/2f9babe73ca644be8734f4bc78da0cfd.png

我的项目

送佛送到西,我还把项目发布到了jitpack

仓库地址

	repositories {maven { url 'https://jitpack.io' }}

要引入以下两个依赖

	dependencies {implementation 'com.github.zhuguohui.Android-Javassist:dx:v1.0.2'implementation 'com.github.zhuguohui.Android-Javassist:javassist-android:v1.0.2'}

项目源码

zhuguohui/Android-Javassist

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“女神节倒计时”给你心爱的她准备惊喜了吗?别着急,闪侠惠递来帮你!

女神节马上就要到了&#xff0c;你给亲爱的她准备惊喜了吗&#xff1f;如果没有&#xff0c;别着急&#xff0c;还有时间可以用心准备准备&#xff0c;如果准备了&#xff0c;你打算怎么送给她呢&#xff1f;当面送给她&#xff1f;快递邮寄给她&#xff1f;可是快递费好昂贵的…

STM32利用标准库编写中断控制oled计数(proteus仿真)

先看先程序效果&#xff1a;每按动一次按钮OLED显示的值加1.这个按键的检测是用中断完成的。 这个工程是在上一个工程&#xff1a;的基础上来完成的&#xff0c;主要是在Mycode文件夹里面新建了两个文件来创建中断的功能方式如下&#xff1a;结构很简单&#xff0c;就是count.c…

【JavaScript】面试手撕浅拷贝

【JavaScript】面试手撕浅拷贝 引入 浅拷贝和深拷贝应该是面试时非常常见的问题了&#xff0c;为了能将这两者说清楚&#xff0c;于是打算用两篇文章分别解释下深浅拷贝。 PS: 我第一次听到拷贝这个词&#xff0c;有种莫名的熟悉感&#xff0c;感觉跟某个英文很相似&#xff…

工业云组态:制造业数字化转型的关键

随着第四次工业革命的到来&#xff0c;数字化转型已成为制造业提升竞争力、实现可持续发展的核心驱动力。在这一背景下&#xff0c;HiWoo Cloud平台推出了工业云组态解决方案&#xff0c;旨在通过云计算、大数据和物联网等先进技术的融合&#xff0c;助力制造业实现智能化、高效…

力扣经典题目解析--最小覆盖子串

原题地址: . - 力扣&#xff08;LeetCode&#xff09; 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 "" 。 注意&#xff1a; 对于 t 中重复字符&#xff0c;我们寻找…

刷题日记:面试经典 150 题 DAY3

刷题日记&#xff1a;面试经典 150 题 DAY3 274. H 指数238. 除自身以外数组的乘积380. O(1) 时间插入、删除和获取随机元素134. 加油站135. 分发糖果 274. H 指数 原题链接 274. H 指数 重要的是都明白H指数到底是是个啥。注意到如果将引用数从大到小排序&#xff0c;则对于…

考研复试指南

1. 记住&#xff0c;复试的本质不是考试&#xff0c;而是一场自我展示。 考研复试并非简单的知识考察&#xff0c;更是一场展示自我能力和潜力的机会。除了学科知识&#xff0c;考官更关注你的综合素质、学术兴趣和未来发展规划。因此&#xff0c;要保持自信&#xff0c;用更全…

机器学习模型总结

多元线性回归&#xff08;linear regression&#xff09; 自变量&#xff1a;连续型数据&#xff0c;因变量&#xff1a;连续型数据 选自&#xff1a;周志华老师《机器学习》P53-55 思想&#xff1a;残差平方和达到最小时的关系式子即为所求&#xff0c;残差平方和&#xff1a…

uniapp 部署h5,pdf预览

1.hubuilderx 打包h5。 2.上传部署包到服务器。 解压部署包&#xff1a;unzip h5.zip 。 3.nginx配置。 user root; worker_processes 1; #worker_cpu_affinity 0001 0010 0100 1000; #error_log logs/error.log; #error_log logs/error.log notice; error_log /var/l…

抖店怎么入驻?具体的入驻流程是什么?新手一看就会!

我是电商珠珠 新的一年开始了&#xff0c;又有不少新手小伙伴入驻了抖店。我做电商已经五年了&#xff0c;做抖店做了三年多&#xff0c;期间带着学员一起做店。所以对于他们所犯的这些操作错误&#xff0c;相信部分新手小伙伴也会犯错&#xff0c;为了让大家少走点弯路&#…

便携式气象站的工作原理

TH-BQX8便携式气象站是一种轻便、易于携带的气象监测设备&#xff0c;它能够快速部署在需要监测的区域&#xff0c;实时监测和记录气象环境数据。与全自动气象监测站相比&#xff0c;便携式气象站更加注重移动性和灵活性&#xff0c;适用于临时性的气象监测任务或特定区域的气象…

【大厂AI课学习笔记NO.58】(11)混淆矩阵

混淆矩阵&#xff08;confusion matrix&#xff09;—— 混淆矩阵&#xff08;Confusion Matrix&#xff09;是人工智能领域&#xff0c;特别是在机器学习和深度学习中&#xff0c;用于衡量分类模型性能的重要工具。它通过统计分类模型的真实分类与预测分类之间的结果&#xf…