1. 程式人生 > >成為大神之路---學會編寫Android Studio外掛 別停留在用的程度了

成為大神之路---學會編寫Android Studio外掛 別停留在用的程度了

一、概述

相信大家在使用Android Studio的時候,或多或少的會使用一些外掛,適當的配合外掛可以幫助我們提升一定的開發效率,更加快樂。例如:

有句話叫做授人以魚不如授人以漁,不能一直跟隨著別人的腳步去使用外掛了,有必要去學習編寫外掛,當自己有好的創意的時候,就可以自己實現了。So,本文的內容是:

  • 自己編寫一個Android Studio外掛

ok,其實編寫外掛並不難,官方也有詳細的文件,所以你也可以選擇直接閱讀下文學習:

為了文章有一定的流暢性,決定以ECTranslation作為編寫Android Studio外掛的例子。

我為什麼選這個呢?因為創意好,實用並且程式碼簡單。

貼一個今天這個外掛的最終效果圖:

注:效果與ECTranslation基本一致,本文僅用作學習,不造輪子,如果需要使用,直接使用ECTranslation即可。

二、準備工作

首先需要安裝IntelliJ IDEA

下載好就可以了~~

然後安裝,執行,點選create New Project:


按照上圖進行選擇,如果沒有SDK,則點選New新建一個即可。

然後點選Next,輸入專案名稱選擇位置,就可以點選finish了。

專案的結構如下:


src目錄下主要用於存放我們編寫的程式碼。

這樣準備工作就結束了~~

三、編碼

(1) 關鍵知識

編碼實際上核心的一個類叫做AnAction,可以直接選擇NEW->Action,如下圖:


然後填寫一些相關資訊:


需要填寫的屬性如下:

  • ActionID:代表該Action的唯一的ID,一般的格式為:pluginName.ID
  • ClassName:類名
  • Name:就是最終外掛在選單上的名稱
  • Description:對這個Action的描述資訊

然後往下,選擇這個Action即將存在的位置:

我們選擇的是EditMenu,右側選擇為first,即EditMenu下的第一個,效果如圖:


再往下就是制定快捷鍵了~~

都填寫完成就可以點選OK了。

點選ok之後,可以看到為我們生成了下類:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">TranslateAction</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">AnAction</span> {</span>
    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">actionPerformed</span>(AnActionEvent e) {
        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// TODO: insert action logic here</span>
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

此外我們剛才填寫的資訊,也在plugin.xml中完成了註冊,大家可以進去看一眼,actions的標籤中,

當我們點選選單的時候,就回觸發actionPerformed()方法。

那麼這麼看,我們在這個方法中只要完成三件事:

  1. 獲得當前選中的單詞
  2. 呼叫相關API得到單詞的意思
  3. 通過一個類似於PopupWindow來顯示

當然,為了儘快的測試,你可以先在裡面彈一個對話方塊,例如如下:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">actionPerformed</span>(AnActionEvent event) {
        Messages.showMessageDialog(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Hello World !"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Information"</span>, Messages.getInformationIcon());
    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

預期效果是點選Tranlate選單,或者按快捷鍵會彈出一個提示對話方塊。

那麼點選Run:


然後它會預設啟動一個新的IntelliJ IDEA的介面,你可以隨便新建一個專案,進入以後,你會發現Edit下多了一個Translate選單,點選即可彈出我們設定的對話方塊:


ok,測試通過就放心了~

  1. 獲得當前選中的單詞
  2. 呼叫相關API得到單詞的意思
  3. 通過一個類似於PopupWindow來顯示

剩下的就是功能性的API了~

(2) 獲得當前選中的單詞

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">actionPerformed</span>(AnActionEvent e) {
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// TODO: insert action logic here</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Editor mEditor = e.getData(PlatformDataKeys.EDITOR);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span> == mEditor) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;
    }
    SelectionModel model = mEditor.getSelectionModel();
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> String selectedText = model.getSelectedText();
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (TextUtils.isEmpty(selectedText)) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>;
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

是不是覺得API很陌生,恩,我也覺得很陌生,關於API這裡介紹其實沒什麼意義,本文主要目的是讓大家對自定義外掛有個類helloworld的認識,至於外掛裡面的程式碼涉及到的API等到大家需要編寫外掛的時候,再詳細學習就好了,現在就不要浪費精力記憶這些東西了。

上面的程式碼就是獲得選中的文字,通過一個Editor,然後拿到SelectionModel,再拿到selectedText,從字面上還是蠻好理解的。

拿到選中的文字之後,應該就是去查詢該單詞的意思了,查詢呢,ECTranslation用的是youdao的Open SDK,其實也很簡單,就是拼接一個url,然後等著解析返回資料就好了。

(3)呼叫相關API得到單詞的意思

有道API的地址:

大家如果想要做單詞翻譯,可以看下,非常簡單。

涉及到的程式碼:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">String baseUrl = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"http://fanyi.youdao.com/openapi.do?keyfrom=Skykai521&key=977124034&type=data&doctype=json&version=1.1&q="</span>;

HttpUtils.doGetAsyn(baseUrl + selectedText, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HttpUtils.CallBack() {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onRequestComplete</span>(String result) {
        Translation translation = gson.fromJson(result, Translation.class);
        showPopupBalloon(mEditor, translation.toString());
    }
});</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

HttpUtils就不貼了,就是直接開了個執行緒,通過HttpUrlConnection去訪問網路,大家的專案中或者通過搜尋引擎,程式碼一搜一堆。

baseUrl就是有道的url,加上我們選中的單詞就是完整的url了,然後通過http訪問,callback回調出返回的字串,這裡返回的是json型別的字串。

baseUri是:

我們根據返回的json字串生成了一個類Translation;

然後通過Gson轉化為Translation物件。

ps:拿著上面的baseUrl後面跟一個任何單詞,直接訪問瀏覽器就能看到返回的json資料了,這裡大家天天寫介面,類似的步驟比我肯定還熟悉。

好了,有了返回的資料以後,直接通過一個類似popupWindow展現即可。

(4)通過一個類似於PopupWindow來顯示

涉及到的程式碼:

<code class="language-java hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">showPopupBalloon</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Editor editor, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> String result) {
    ApplicationManager.getApplication().invokeLater(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Runnable() {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() {
            JBPopupFactory factory = JBPopupFactory.getInstance();
            factory.createHtmlTextBalloonBuilder(result, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> JBColor(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Color(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">186</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">238</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">186</span>), <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Color(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">73</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">117</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">73</span>)), <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>)
                    .setFadeoutTime(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5000</span>)
                    .createBalloon()
                    .show(factory.guessBestPopupLocation(editor), Balloon.Position.below);
        }
    });
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

這個API,恩,我copy的原始碼,依然是不求記住,知道這有個類似的功能即可。

簡單看一下,是通過建立一個JBPopupFactory,然後通過它建立一個HtmlTextBalloonBuilder,通過這個builder去設定各種引數,最後show。

ok,對於一個入門的例子,不要太強求對外掛中這些API的掌握,還是那句話,等需要寫了再去查,需要什麼功能,哪怕到對應的外掛中去copy原始碼都可以,當然也有文件:

有興趣的可以整理各種型別的外掛,比如彈出popupWindow,生成程式碼,生成檔案類別的,然後對相關的API進行收集與整理。

這樣程式碼寫完了,先測試一下,點選RUN,然後看效果~

我們這裡肯定是測試沒問題的,效果圖就是開始的那個gif.

如果沒有問題,就可以去部署和釋出我們的外掛給別人去使用了。

這兩部也非常簡單。

四、部署外掛

(1)填寫外掛相關資訊

開啟專案檔案的plugin.xml,如下圖:


在裡面填寫id,name,version等。。。記得隨便填一下~

然後,點選build->prepare plugin…,如下圖:


會在專案的根目錄生成一個jar,如圖:


這個jar就可以用於安裝了。

(2)安裝外掛

開啟Andorid Studio,選擇Preferences -> Plugins -> Install plugin from disk,選擇我們生成的jar即可,如圖:


點選安裝,然後重啟即可。

好了,重啟完成就可以在EDIT下看到Translate選單了,選中單詞,點選選單或者快捷鍵都能實現翻譯了。

如果你有興趣,趕緊編寫一個外掛自己玩吧。

當然,還可以把我們的外掛釋出到倉庫,支援在plugin中搜索安裝,參考:

就是註冊賬號,提交jar,填寫資訊,等著稽核就可以了。

五、總結

終於到了總結的環節,這麼長的文章其實編寫外掛總結起來就幾句話。

  1. 下載Intellij IDEA,新建一個Intellij IDEA plugin的專案
  2. 然後在裡面new Action以及編寫API
  3. 點選prepare plugin生成jar,這個jar就可以用來安裝了。

恩,就是這麼簡單,實踐起來會比較麻煩一點,等成功以後,回過頭來總結,發現步驟其實就那麼幾個步驟~~對於實際的Action相關的API,等你在編寫相關外掛的時候,參考別的類似外掛,檢視官方文件都可以。

轉自:http://blog.csdn.net/lmj623565791/article/details/51548272