目录

实现效果
首先是加载第一种实现效果

然后是加载第二种实现效果

这两种效果都是通过动态加载想要执行的Class来实现的,其中要执行的Class中方法的逻辑可以随意替换,从而实现百变功能的方法,而这所有的实现都不需要重新安装APK
实现原理
这里的实现原理是借鉴了热修复的原理,其实就是利用DexClassLoader加载多种逻辑的Class从而实现百变方法,原理图大致如下所示:

先定义一个MethodProxy接口,然后定义MethodImpl实现MethodProxy接口,其中MethodImpl实现exec方法,exec方法可以实现多种逻辑,然后将每一种实现的逻辑所生成的class文件打包成dex文件,然后通过DexClassLoader加载这些逻辑不同但类名相同的Class,最终通过MethodProxy来对外统一执行exec方法
相关文章
实现步骤
1.定义MethodProxy接口
public interface MethodProxy {
void exec(Context context);
}
2.实现MethodProxy接口
public class MethodImpl implements MethodProxy{
@Override
public void exec(Context context) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage("我是消息");
builder.setTitle("提示");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
}
3.获得MethodImpl的class文件
通过运行应用即可得到MethodImpl 的class文件,在如下位置

4.打包class文件
我们可以通过build-tools中的dx.bat将class文件打包成dex文件

在这之前我们先将dx.bat加入到Path环境变量中

由于我们只需要MethodImpl的class文件因此我们可以将其他的class文件排除

将无关的删除

然后我们回到debug目录

在该目录下打开命令行窗口执行如下命令
dx --dex --output=out.dex classes
该命令的意思是将classes下的文件打包为out.dex文件,执行完后生成out.dex文件

5.加载Class
首先我们先将out.dex放到SD卡中

我们在Activity中加载此dex中的Class,并执行exec方法
public class MainActivity extends AppCompatActivity {
private DexClassLoader dexClassLoader;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initClass();
}
private void initClass() {
try {
File dexDir = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),"/dex");
File dexFile = new File(dexDir,"out.dex");
dexClassLoader = new DexClassLoader(dexFile.getAbsolutePath(),dexDir.getAbsolutePath(),null,getClassLoader());
}catch (Exception e){
Log.e("加载",e.getMessage());
}
}
public void onClick(View view) {
try {
Class<?> methodImplClazz = dexClassLoader.loadClass("com.itfitness.dexclassloaderdemo.MethodImpl");
MethodProxy methodProxy = (MethodProxy) methodImplClazz.newInstance();
methodProxy.exec(this);
}catch (Exception e){
Log.e("加载",e.getMessage());
}
}
}
然后为了确保我们是执行的dex中的Class我们需要将项目中的MethodImpl文件删除


然后我们重新运行项目,效果如下

网友评论