本篇是AS插件开发的入门篇,旨在了解整个开发流程,代码比较粗糙
AS插件绝对是我们开发道路上的一把利器,这里首先推荐几款我常用的插件。
Json转Java类
快速生成findViewById代码
CodeGlance:
工欲善其事,必先利其器。首先我们要先准备IDE,这里使用 Intellij,我下载的Community版。
安装完毕后,新建一个插件开发工程:
关于project SDK
,要说一下。如果没有sdk
,就点击New
,选择软件附带的,但是这里可能会提示没有Java jdk
,在自己本机上,随便找一个版本的jdk
就行,我用的1.8。
新建好的工程目录如下:
我们接下来模仿ECTranslation写一个翻译插件,因为原理简单,使用方便,实现起来很容易。大家如果看明白原理,都可以自己动手做一个。
因为要用到有道翻译的API,所以我们要先在有道智云上注册开发者,注册完申请自然语言翻译服务,创建应用。
请求API的过程有道翻译已经给我们准备好了Demo
我直接贴出来Java的请求过程:
public class Demo {
public static void main(String[] args) throws Exception {
String appKey ="您的appKey";
String query = "good";
String salt = String.valueOf(System.currentTimeMillis());
String from = "EN";
String to = "zh-CHS";
String sign = md5(appKey + query + salt+ "您的密钥");
Map params = new HashMap();
params.put("q", query);
params.put("from", from);
params.put("to", to);
params.put("sign", sign);
params.put("salt", salt);
params.put("appKey", appKey);
System.out.println(requestForHttp("https://openapi.youdao.com/api", params));
}
public static String requestForHttp(String url,Map requestParams) throws Exception{
String result = null;
CloseableHttpClient httpClient = HttpClients.createDefault();
/**HttpPost*/
HttpPost httpPost = new HttpPost(url);
List params = new ArrayList();
Iterator> it = requestParams.entrySet().iterator();
while (it.hasNext()) {
Entry en = it.next();
String key = en.getKey();
String value = en.getValue();
if (value != null) {
params.add(new BasicNameValuePair(key, value));
}
}
httpPost.setEntity(new UrlEncodedFormEntity(params,"UTF-8"));
/**HttpResponse*/
CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
try{
HttpEntity httpEntity = httpResponse.getEntity();
result = EntityUtils.toString(httpEntity, "utf-8");
EntityUtils.consume(httpEntity);
}finally{
try{
if(httpResponse!=null){
httpResponse.close();
}
}catch(IOException e){
e.printStackTrace();
}
}
return result;
}
/**
* 生成32位MD5摘要
* @param string
* @return
*/
public static String md5(String string) {
if(string == null){
return null;
}
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F'};
try{
byte[] btInput = string.getBytes("utf-8");
/** 获得MD5摘要算法的 MessageDigest 对象 */
MessageDigest mdInst = MessageDigest.getInstance("MD5");
/** 使用指定的字节更新摘要 */
mdInst.update(btInput);
/** 获得密文 */
byte[] md = mdInst.digest();
/** 把密文转换成十六进制的字符串形式 */
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (byte byte0 : md) {
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
}catch(NoSuchAlgorithmException | UnsupportedEncodingException e){
return null;
}
}
/**
* 根据api地址和参数生成请求URL
* @param url
* @param params
* @return
*/
public static String getUrlWithQueryString(String url, Map params) {
if (params == null) {
return url;
}
StringBuilder builder = new StringBuilder(url);
if (url.contains("?")) {
builder.append("&");
} else {
builder.append("?");
}
int i = 0;
for (String key : params.keySet()) {
String value = params.get(key);
if (value == null) { // 过滤空的key
continue;
}
if (i != 0) {
builder.append('&');
}
builder.append(key);
builder.append('=');
builder.append(encode(value));
i++;
}
return builder.toString();
}
/**
* 进行URL编码
* @param input
* @return
*/
public static String encode(String input) {
if (input == null) {
return "";
}
try {
return URLEncoder.encode(input, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return input;
}
}
开发前,先讲下翻译的原理。整个翻译的过程很简单,获取鼠标选择的单词,调用翻译API,整理翻译结果并显示。
这里使用的是有道翻译的API,新版有道智云的自然语言翻译API已经不免费了,不过用户注册以后会送100块的体验金,其收费标准如下:
如果是我们自己个人使用,100块也足够我们折腾了。
接下来进入正式的开发过程。
首先新建一个Action文件:
然后填入Action ID、Class Name、快捷键:
上图中我们把新加的翻译按钮放在Edit
命令下,命令的名字叫translation
,快捷键是Alt+E
。
确定以后,看一眼plugin.xml
里多了这样一段代码:
"zttranslation" class="ZTTranslation" text="Translation" description="translate word" icon="/icons/ic_logo.png">
"EditMenu" anchor="first"/>
"$default" first-keystroke="alt E"/>
这是我们新建的翻译Action对应的配置文件。这里扩展一下,上面配置文件中,我给自己的Action前加了个图标,就像这样:
我们可以在resources目录下新建icons目录,并添加icon图片(后缀为)
然后在配置文件中添加对应的配置即可:icon="/icons/ic_logo.png"·
。当AS的主题变为黑色时,Action的logo会自动使用后缀为dark的logo图。
下面我们看一眼新建的ZTTranslation
类:
public class ZTTranslation extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
// TODO: insert action logic here
}
}
接下来我们要获取鼠标选择的单词并弹框显示:
public class ZTTranslation extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
final Editor mEditor = e.getData(PlatformDataKeys.EDITOR);
if (null == mEditor) {
return;
}
SelectionModel model = mEditor.getSelectionModel();
final String selectionTxt = model.getSelectedText();
if (TextUtils.isEmpty(selectionTxt)) {
return;
}
Messages.showMessageDialog(selectionTxt,"TestWord",Messages.getInformationIcon());
}
}
运行一下看看效果。
运行以后会重新打开一个新窗口,随便新建一个工程,看下Edit命令下:
我们新建的Translation
在第一行,下面测试下,选择单词:
一切正常,接下来我们继续往下接入翻译。
@Override
public void actionPerformed(AnActionEvent e) {
final Editor mEditor = e.getData(PlatformDataKeys.EDITOR);
if (null == mEditor) {
return;
}
SelectionModel model = mEditor.getSelectionModel();
final String selectionTxt = model.getSelectedText();
if (TextUtils.isEmpty(selectionTxt)) {
return;
}
//调用有道翻译Demo
String result = HttpUtils.findTranslation(selectionTxt);
StringBuilder sb = buildResult(result);
String translation;
if (sb.length() == 0) {
translation = "暂无此翻译!";
} else {
translation = sb.toString();
}
showTranslationPopup(mEditor, translation);
}
HttpUtils.findTranslation(selectionTxt)
就是上面我贴出来的有道官网上的请求Demo,然后将返回的字符串按照设计的思路重新排版一下,翻译请求的返回结果示例如下:
{
"errorCode":"0",
"query":"good", //查询正确时,一定存在
"translation": [ //查询正确时一定存在
"好"
],
"basic":{ // 有道词典-基本词典,查词时才有
"phonetic":"gʊd"
"uk-phonetic":"gʊd" //英式发音
"us-phonetic":"ɡʊd" //美式发音
"explains":[
"好处",
"好的"
"好"
]
},
"web":[ // 有道词典-网络释义,该结果不一定存在
{
"key":"good",
"value":["良好","善","美好"]
},
{...}
]
],
"dict":{
"url":"yddict://m.youdao.com/dict?le=eng&q=good"
},
"webdict":{
"url":"http://m.youdao.com/dict?le=eng&q=good"
},
"l":"EN2zh-CHS"
}
我这里只取了“explains”的翻译结果,然后弹出一个popup显示:
private void showTranslationPopup(final Editor editor, final String result) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
JBPopupFactory factory = JBPopupFactory.getInstance();
factory.createHtmlTextBalloonBuilder(result, null, new JBColor(new Color(186, 238, 186), new Color
(73, 117, 73)), null).setFadeoutTime(5000).createBalloon().show(factory
.guessBestPopupLocation(editor), Balloon.Position.below);
}
});
}
然后再运行看看,英译汉:
汉译英:
这里只是一个练习的例子,所以没考虑更多细节,不过以后看源码应付下生僻单词还是很给力的,哈哈。
最后就是编译并导出插件包,运行到我们的Android Studio上去。
插件zip包就导出到工程路径下了,然后我们赶紧打开AS安装插件试试。
安装完成以后重启AS就可以了。
现在我们准备好了插件,如果相认更多的人搜索到它,就得把它发布到插件仓库中,下面我们看看发布流程。
默认的配置文件长这样:
<idea-plugin version="2">
<id>com.your.company.unique.plugin.idid>
<name>Plugin display name herename>
<version>1.0version>
<vendor email="[email protected]" url="http://www.yourcompany.com">YourCompanyvendor>
<description>
most HTML tags may be used
]]>description>
<change-notes>
most HTML tags may be used
]]>
change-notes>
<idea-version since-build="141.0"/>
<extensions defaultExtensionNs="com.intellij">
extensions>
<actions>
actions>
idea-plugin>
我们需要填写一些关键信息,其中 description
必须用英文,否则提交到市场后,会被官方打回。description
支持html标签,不熟悉的可以直接使用在线Html编辑器。
还要需要注意的是这段:
这里是配置你的插件发布到jetbrains插件仓库的产品类型。
我们都知道jetbrains公司产品很多,比如我们常用的Android Studio,Intellij等,这些都支持插件。
如果我们注释上面的代码,那么我们的插件会默认上传到Intellij仓库,也就是说别人只能在Intellij中搜索到我们的插件,在AS中找不到……所以我们把注释去掉,就可以默认上传到所有仓库啦。
配置好信息后,我们需要重新编译生成插件。
准备好了插件信息以后,我们需要去注册仓库账号:Jetbrains Plugins Repository
上传以后需要官方审核,然后会给我们的注册邮箱发送反馈信息,如果我们的配置文件格式不对,比如我最开始使用了中文描述,就会被市场拒掉……
如果一切正常,一两个工作日后就会收到官方恭喜的邮件~然后我们就可以在仓库中搜索到啦。