您的位置:首页 > 移动开发 > Android开发

Android studio插件开发实战(4)-CodeGenerator插件开发

2016-02-24 14:20 351 查看
  上一篇文章分析了FindViewByMe插件的实现,这篇文章对它进行扩展,开发一款CodeGenerator插件。

扩展点1——newActivityInstance

  首先想到的一个扩展点是自动生成activity的newInstance方法,作用是启动一个页面同时传递参数,因为每次去构造Intent传值再从Intent里取值都高度模板化,每次手写很烦,完全可以用插件自动生成。

  上一张效果图:

  


扩展点2——动态自定义模板

  第二个扩展点是自动转换字符,比如我们的接口名字可能是”home.login”,我们想将它定义成常量,并添加注释:

/**
* Comments
**/
public static final String HOME_LOGIN = "home.login";


  网络请求可能是这样的:

/**
* Comments
**/
public void homeLogin() {
NetworkParam param = new NetworkParam (Constants.HOME_LOGIN );
...
}


  也是模板化的代码。实现起来其实非常简单,就是简单的字符串操作。但是如果仅仅实现固定的转换未免太弱了,有一个小小的改动都要修改插件。能不能动态执行代码呢?

  要实现动态执行代码有两种方式,第一种类似Excel里的脚本函数,定义一些CONCATENATE,SUBSTITUTE内置函数,根据函数做相应的操作。自己定义一套函数肯定不是做好的方式,费时费力又很难做好。第二种方式是直接执行java代码。定义一个java方法,拼接好字符串然后返回,没有任何学习新的函数的成本!

  Java是真正的动态语言,可以在运行时利用反射机制动态调用对象的方法

  首先找到了这两篇文章,java中动态执行一段代码Java中动态加载jar文件和class文件无非是三部曲:生成java文件;编译成class文件;使用invoke方法执行方法。但是在执行第三步时怎么都报ClassNotFoundException for PluginClassLoader ,也就是插件的ClassLoader 无法装载我们编译出的class文件。把所有能试的ClassLoader试了一遍还是不行。无奈只能拼命搜索ClassLoader的内容,但是把关于Intellij 插件加载器的内容实在太少了。

  最后只能去看JVM的知识了。很快,在深入理解Java虚拟机:JVM高级特性与最佳实践(第2版) 第九章找到了完美的解决方案。

  首先我们要自定义一个ClassLoader,HotSwapClassLoader,如下:

public class HotSwapClassLoader extends ClassLoader{
public HotSwapClassLoader() {
super(HotSwapClassLoader.class.getClassLoader());
}

public Class loadByte(byte[] classByte) {
return defineClass(null, classByte, 0, classByte.length);
}
}


  它只做了一件事,将ClassLoader的protected方法defineClass变为public,这样就可以动态将class文件加载进虚拟机了。其实到这里问题已经解决了,类加载进来就可以执行成员方法了,执行结果可以通过字符串返回。

  在书中作者又额外做了一步,将输入类的byte数组中代表java.lang.System的CONSTANT_Utf8_info常量修改为劫持后的HackSystem类,输出结果为该类向System.out/err输出的信息(具体做法请参加代码)。

  


遗留问题

  1、jdk版本不兼容问题,用java7 / 8 编译出的插件放到运行环境是java8 / 7的开发环境会不识别,目前只能分别使用java7和8编译出两个插件一起放到android studio插件目录。

源代码

  最后附上github地址, 可以直接下载CodeGenerator-jdk1.7.jar、CodeGenerator-jdk1.8.jar两个包放到android studio 的plugins目录下使用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android studio 插件