使用Javassist 在android运行时生成类

news2024/11/15 21:09:02

序言

最近在写框架,有一个需求就是动态的生成一个类,然后查阅了相关文献,发现在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;


    @Override
    public 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() {
					@Override
					public 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();
        	}
        }
    }

    @Override
    public 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.coloradmin.cn/o/1491058.html

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

相关文章

Java动态转发代理IP的实现方法

目录 前言 一、代理IP池的管理 二、代理IP的请求转发 总结 前言 在某些情况下&#xff0c;我们可能需要在Java应用程序中使用代理IP来进行网络请求。而有时候&#xff0c;我们希望能够动态地切换代理IP&#xff0c;以增加请求的成功率和效果。本文将介绍如何在Java中实现动…

【深度学习笔记】5_8 网络中的网络NiN

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 5.8 网络中的网络&#xff08;NiN&#xff09; 前几节介绍的LeNet、AlexNet和VGG在设计上的共同之处是&#xff1a;先以由卷积层构成的…

深度学习_16_权重衰退调整过拟合

所谓过拟合即模型复杂度较高&#xff0c;但用于训练数据集过于简单&#xff0c;最后导致模型将过多无用渣质作为学习对象 这个在上篇 深度学习_15_过拟合&欠拟合 已经详细介绍&#xff0c;以下便不再赘述。 上篇提到要想解决过拟合现象可以试着降低模型复杂度&#xff0c…

边缘计算网关在机床生产中的应用-天拓四方

随着工业4.0的推进&#xff0c;物联网&#xff08;IoT&#xff09;技术在各个工业领域中的应用日益广泛。特别是在机床行业&#xff0c;物联网技术的引入不仅提高了生产效率&#xff0c;还实现了对机床设备的实时监控和远程维护。在这一背景下&#xff0c;边缘计算网关的角色愈…

牛客网 计算某个字符出现的次数

在本题中&#xff0c;我们是要统计一个字符串中重复字母出现的次数&#xff0c;我们把输入的字母转换成小写&#xff0c;然后把字符串也都转换成小写&#xff0c;然后把字符串中包含字母的地方替换成空。然后直接用字符串减去替换完成的字符串&#xff0c;就是我们要统计的个数…

c++ opecv项目实战

1、银行卡识别项目 参考文章 操作流程&#xff1a; 1、提取模板的每个数字 读取图片->转换为灰度图像->二值化图像(大于10取0&#xff0c;小于取255)->轮廓检测->绘制轮廓->对所有轮廓进行排序->提取模板所有轮廓每个数字 2、读取信用卡->转换为灰度图像…

unity Game视图看不到贴花,但是在Scene视图能看到

解决方法&#xff1a;找到URP的配置文件 &#xff0c;修改Quality–RederScale为1&#xff0c;就可以了&#xff0c;这是unity 的bug&#xff0c;2022版本以后就没有这个问题了

09 Qt扩展LineEdit组件:Input输入框

系列文章目录 01 Qt自定义风格控件的基本原则-CSDN博客 02 从QLabel聊起&#xff1a;自定义控件扩展-图片控件-CSDN博客 03 从QLabel聊起&#xff1a;自定义控件扩展-文本控件-CSDN博客 04 自定义Button组件&#xff1a;令人抓狂的QToolButton文本图标居中问题-CSDN博客 0…

ROS读书记录1:机器人SLAM导航核心技术与实战1

机器人SLAM导航核心技术与实战1 第一章第2章 ROS简介 视频参考&#xff1a; 《机器人SLAM导航核心技术与实战》书籍配套教学视频 第一章 第2章 ROS简介 ROS:机器人开发平台 ①ROS是一个分布式通信框架(最核心的本质 ②ROS是一个开发工具的集台 ③ROS是一系列开源软件包 计算…

OpenDDS之QosXml库编译(Windows + VS2019)

目录 1、需求背景2、基础环境3、编译xercesc3.1、下载xercesc3.2、编译xercesc 4、编译ACE_XML_Utils4.1、生成XML_Utils解决方案4.2、编译XML_Utils 5、编译QOS_XML_XSC_Handlerd5.1、生成QOS_XML_XSC_Handlerd解决方案5.2、编译QOS_XML_XSC_Handlerd 6、测试例子6.1、生成dum…

百度文库旋转验证码识别

最近研究了一下图像识别&#xff0c;一直找到很好的应用场景&#xff0c;今天我就发现可以用百度的旋转验证码来做一个实验。没想到效果还挺好&#xff0c;下面就是实际的识别效果。 1、效果演示 2、如何识别 2.1准备数据集 首先需要使用爬虫&#xff0c;对验证码图片进行采…

leetcode最大二叉树

在本题中&#xff0c;我们是要将给定的数组构成一个二叉树&#xff0c;其根节点是数组中最大的元素&#xff0c;左子树都是最大值左边元素组成的&#xff0c;右子树都是最大值右边元素组成的。所以本题的关键在于我们先需要找到最大的元素。 我们构造二叉树&#xff0c;一般是采…

Vue.js 实用技巧:深入理解 Vue.mixin

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

商业数据增长超88%!小红书热门内容解析,用户“打卡”新玩法

长久以来&#xff0c;“打卡”在社交媒体盛行&#xff0c;频频涌现新风潮&#xff0c;几乎覆盖美食、旅游、美妆等众多热门行业&#xff0c;今天吃了什么、玩了什么、做了什么&#xff1f;大众都喜欢通过打卡来分享。特别是小红书平台&#xff0c;打卡内容热度经久不衰&#xf…

LeetCode Python - 31.下一个排列

目录 题目答案运行结果 题目 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。 例如&#xff0c;arr [1,2,3] &#xff0c;以下这些都可以视作 arr 的排列&#xff1a;[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。 整数数组的 下一个排列 是指其整数的下一个字典序更…

xss.haozi.me:0x03及04

这里有一个正则所以&#xff08;&#xff09;要用到实体编码 <a href"javascript:alert1">cc</a> 03 04都一样

Softmax 回归 + 损失函数 + 图片分类数据集【动手学深度学习v2】李沐动手学深度学习课程笔记

目录 Softmax回归 损失函数 图片分类数据集 Softmax回归从零开始实现 Softmax回归简洁实现 Softmax回归 回归和分类的区别 回归问题举例上节课的预测房价问题&#xff0c;分类问题就是对样本进行分类 回归和分类的具体区别 假设真实的类别为第i个类别&#xff08;值为1&#x…

掌握WhatsApp手机号质量评分:增加信息可达性

WhatsApp手机号质量评分是用于衡量用户手机号与平台互动的健康度&#xff0c;确保用户通讯时的合规性和安全性。在实掌握WhatsApp手机号质量评分实际应用中&#xff0c;这个评分会影响用户的消息发送的可达性。高质量的评分意味着用户的账户被视为可信赖的&#xff0c;其发送的…

知识点碎片一,物联网通信协议和技术

loT通信协议 1. 前言 本文属于老吴个人对物联网研发学习的路线整理&#xff0c;属于个人对物流网产品研发的知识碎片的学习&#xff0c;文章没有先后顺序&#xff0c;随笔记录。文章如果有错误&#xff0c;希望各位读者指出问题所在&#xff0c;老吴将不胜感激。 2. 名称概述…

动网格学习:如何系统学习,案例及相关学习内容目录-学习材料

一、学习文章及相关案例 动网格&#xff08;Moving Mesh&#xff09;是一种在数值模拟中用于处理流动区域随时间变化的技术。在流体动力学模拟中&#xff0c;当物理模型或某些区域的网格需要随着流动的进行而动态改变时&#xff0c;就会采用动网格技术。例如&#xff0c;在模…