为了提高自己开发Android的效率,用过几款别人写的插件,或许每个人编程习惯不一样,别人插件虽然好用,不免要改这改那。so打算自己开发一款符合自己的插件(其实很简单,也就是findViewById,相信你也也是又爱又恨),顺便学习一下AS的插件开发。
环境搭建
Android Studio 是基于 IntelliJ IDEA 开发的,但是并不支持插件开发,我们需要下载 IntelliJ IDEA 来开发,官网下载地址:https://www.jetbrains.com/idea/,下载Community版本就行!
安装也简单,不做详解!!
创建项目
目录结构
这里简单说一下项目自动生成的插件配置文件(plugin.xml):
<idea-plugin>
<!-- 插件的ID,保证插件上传仓库后的唯一性 -->
<id>com.your.company.unique.plugin.id</id>
<!-- 插件名称 -->
<name>Plugin display name here</name>
<!-- 插件版本 -->
<version>1.0</version>
<!-- 插件供应商 -->
<vendor email="support@yourcompany.com" url="http://www.yourcompany.com">YourCompany</vendor>
<!-- 插件简洁 -->
<description><![CDATA[
Enter short description for your plugin here.<br>
<em>most HTML tags may be used</em>
]]></description>
<!-- 插件的更新信息 -->
<change-notes><![CDATA[
Add change notes here.<br>
<em>most HTML tags may be used</em>
]]>
</change-notes>
<!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html for description -->
<idea-version since-build="145.0"/>
<!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
on how to target different products -->
<!-- uncomment to enable plugin in all products
<depends>com.intellij.modules.lang</depends>
-->
<!-- 插件的扩展组件注册 -->
<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
</extensions>
</idea-plugin>
添加Action
右击包名(没有创建包名,右击src),创建Action
OK之后会出来一个继承AnAction的实现类,里面会有个方法:
public class InitViewAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent event) {
}
}
当我操作该Action快捷键或者选择该Action菜单,actionPerformed方法就会执行。
同时还会在插件配置文件(plugin.xml)添加action:
<actions>
<!-- Add your actions here -->
<action id="InitView.ID" class="com.johan.initview.InitViewAction" text="InitView" description="create init view method">
<add-to-group group-id="CodeMenu" anchor="first"/>
<keyboard-shortcut keymap="$default" first-keystroke="alt V"/>
</action>
</actions>
这些都是我们刚才设置的内容,都是可以改的,比如快捷键冲突了,改一下first-keystroke就行了!
实现功能
我们的功能实现都要写在Action的actionPerformed方法内,我要的是初始化View的小功能,分4步:
1.获取选中内容
2.获取布局文件
3.解析布局文件
4.生成初始化View的代码
获取选中内容
// 获取project
Project project = event.getProject();
if (project == null) {
return;
}
// 获取选中内容
final Editor editor = event.getData(PlatformDataKeys.EDITOR);
if (editor == null) {
return;
}
String selectedText = editor.getSelectionModel().getSelectedText();
// 如果没有选中内容,提示选择布局
if (StringUtils.isEmpty(selectedText) || !StringUtils.startsWith(selectedText,"R.layout.")) {
// 类似于Android的toast
ViewUtils.showPopupBalloon(editor, "请选择布局id");
return;
}
全都是Java代码,可以看出,其实 IntelliJ IDEA 也是Java写的(我猜的)。但是其API相对陌生,我们没必要对每个API都要了解,用到时再去查就行了。
获取布局文件
String layoutFileName = selectedText.substring(9) + ".xml";
// 通过文件名查找布局文件
PsiFile[] getFiles = FilenameIndex.getFilesByName(project, layoutFileName, GlobalSearchScope.allScope(project));
// 如果没有找到,提示没有找到布局文件
if (getFiles == null || getFiles.length == 0) {
// 类似于Android的toast
ViewUtils.showPopupBalloon(editor, "没有找到布局文件:" + layoutFileName);
return;
}
解析布局文件
// 解析XML
XmlFile layoutFile = (XmlFile) getFiles[0];
List<Element> elementList = new ArrayList<>();
Utils.parseXmlLayout(layoutFile, elementList);
if (elementList.size() == 0) {
ViewUtils.showPopupBalloon(editor, "没有找到任何id");
return;
}
// ViewUtils类
public static void parseXmlLayout(final PsiFile xmlLayoutFile, final List<Element> elementList) {
xmlLayoutFile.accept(new XmlRecursiveElementVisitor(){
@Override
public void visitElement(PsiElement element) {
super.visitElement(element);
if (element instanceof XmlTag) {
XmlTag tag = (XmlTag) element;
// 解析XmlTag,保存到elementList中
}
});
}
生成初始化View的代码
// 写入文件,不允许在主线程中进行实时的文件写入
PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project);
PsiClass psiClass = Utils.getTargetClass(editor, psiFile);
InitViewCreator creator = new InitViewCreator(project, psiFile, psiClass, elementList);
creator.execute();
因为不允许在主线程中进行实时的文件写入,所以要使用Simple类:
public class InitViewCreator extends WriteCommandAction.Simple {
@Override
protected void run() throws Throwable {
// 生成Java代码
}
}
我们可以利用PsiElementFactory帮我们生成PsiClass或者PsiMethod所需要的类,PsiElementFactory可以把我们拼凑的方法(字符串)或者字段(字符串)包装成PsiElement。
// 获取PsiElementFactory
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
// 生成字段(插入类中)
String field = "private TextView textView;"
factory.createFieldFromText(field, psiClass)
// 生成方法(插入类中)
String method = "public void onClick(View view){\n\n}"
factory.createMethodFromText(method, psiClass)
// 生成语句(插入方法中或者某一块代码块内)
String code = "textView = (TextView) findViewById(R.id.text_view);"
factory.createStatementFromText(code, psiClass);
上面PsiElementFactory生成的PsiElement就可以加入到class或method或代码块中了:
// class插入字段
psiClass.add(factory.createFieldFromText(field, psiClass));
// class插入方法
String method = "public void onClick(View view){\n\n}"
psiClass.add(factory.createMethodFromText(method, psiClass));
// 方法插入语句
String code = "textView = (TextView) findViewById(R.id.text_view);"
psiMethod.getBody().add(factory.createStatementFromText(code, psiClass));
其实还有很多api,如获取类所有字段和所有方法等,你一看,应该就可以理解的,慢慢体会。遇到不懂的,可以查阅文档:http://www.jetbrains.org/intellij/sdk/docs/tutorials.html
生成所需要的代码后,最后就重写class
public class InitViewCreator extends WriteCommandAction.Simple {
@Override
protected void run() throws Throwable {
// 生成Java代码
// 重写class
JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(project);
styleManager.optimizeImports(psiFile);
styleManager.shortenClassReferences(psiClass);
new ReformatCodeProcessor(project, psiClass.getContainingFile(), null, false).runWithoutProgress();
}
}
测试
码完代码后,就可以测试功能了,点击启动:
会打开一个新的窗口,点击【code】菜单,发现多了一个我们自定义的菜单【InitView】
然后随便新建一个java项目,测试是否会自动生成代码即可,这里不做演示。
生成插件
测试完后,没什么问题,就可以发布了,很简单,点击【build】菜单下的【Prepare Plugin Module xx Fro Deployment】
项目目录会多一个jar包:
这就是你开发的插件了!!开心吧!!
在Android Studio使用插件
打开 Android Studio,点击【File】->【Setting】,选择【Plugins】,点击【install plugin from disk …】
然后选择刚才build出来插件(就是刚才生成的jar包),然后重启 Android Studio
Android Studio 启动后,插件便会生效
发布
有兴趣的话,可以把开发的插件发布到仓库,支持在plugin中搜索安装,参考:
就是注册账号,提交jar,填写信息,等着审核就可以了。
项目地址
我把 InitView 代码上传到我的github库中,地址:https://github.com/JohanMan/InitViewPlugin,有兴趣的可以参考一下。
参考资料
学会编写Android Studio插件 别停留在用的程度了
自己编写Android Studio插件