Android Sutdio ( Intellij ) 插件開發(fā)

先給代碼:
https://github.com/shenjiajun53/TinyPic 喜歡請(qǐng)給個(gè)star

TinyPic 介紹

一個(gè)Intellij的插件,不僅僅是在Android Studio中使用,可以在所有Jetbrains的IDE中使用
功能:壓縮圖片資源,一次最多壓縮500張
壓縮的核心功能是TinyPng這個(gè)網(wǎng)站提供的

https://tinypng.com/

但是這個(gè)網(wǎng)站一次只能上傳20張圖片,所以你需要上傳下載,上傳下載重復(fù)工作。
好在這個(gè)網(wǎng)站提供了api可以壓縮圖片。

在開發(fā)者頁(yè)面下申請(qǐng)api key。對(duì)于一個(gè)key,每月有500次的免費(fèi)壓縮額度,如果壓縮超過了
500張圖片,就不能使用了。需要另外付費(fèi)。但是申請(qǐng)這個(gè)api特別簡(jiǎn)單,填下郵箱,用戶名就行,多申請(qǐng)
兩個(gè)郵箱。1000張圖片也妥妥夠了。
這里推薦google個(gè)十分鐘郵箱,不需要注冊(cè),只能使用十分鐘,用來收一下驗(yàn)證碼很方便

tinypng_develop.png

使用方式

1.在File->Settings->Plugins里下載插件 TinyPic

2.安裝完后重啟,在Tools目錄下找到TinyPic

location.png

3.輸入在 https://tinypng.com/developers 申請(qǐng)的api key

input_key.png

4.選擇圖片,可以選擇圖片,或者選擇文件夾或者同時(shí)選中,反正是遍歷文件夾下的圖片,篩選jpg和png
,key的剩余次數(shù)

select_images.png

5.壓縮進(jìn)度

progress.png

6.超過500次的提示(后續(xù)會(huì)考慮加入 生成壓縮的信息的文件,因?yàn)榇蠹叶加胓it,其實(shí)也不是很必要)

warning.png

為什么做這個(gè)插件

之前在做apk瘦身的時(shí)候考慮到,相比代碼,圖片才是占了更多大小,減少圖片大小有兩步。
1.用Android Studio的lint工具,自動(dòng)刪除沒有引用的資源,這一步需要注意,有些名字是拼接起來的資源也可能被刪除。
2.壓縮圖片,但是考慮到?jīng)]有好用的工具,我決定自己開發(fā)個(gè)插件

下面是開發(fā)過程

http://www.jetbrains.org/intellij/sdk/docs/index.html 這個(gè)是官方文檔

這是我看過的最爛的文檔之一,但是Intellij插件開發(fā)這方面文檔很少,將就著看吧

1.下載Intellij社區(qū)版,社區(qū)版是免費(fèi)的,而且調(diào)試插件更方便,所以推薦這個(gè)

https://www.jetbrains.com/idea/

2.new project 選擇 Plugin

new_project.png

3.項(xiàng)目右擊->Open Module Settings->SDKs 選擇Intellij安裝目錄

add_sdk.png

4.添加action,這個(gè)action其實(shí)就是個(gè)用戶操作的事件,比如說點(diǎn)擊按鈕,
需要填幾個(gè)信息,Id,Name,插件位置

add_action.png

創(chuàng)建完之后生成了一個(gè)Action類,另外在plugin.xml文件下,多了一段代碼

<actions>
        <!-- Add your actions here -->
        <action id="com.shenjiajun.TinyAction" class="com.shenjiajun.TinyAction" text="TinyPic" description="com.shenjiajun.TinyAction"
                icon="/icons/drawable-mdpi/ic_photo_size_select_large_pink_500_18dp.png">
            <add-to-group group-id="ToolsMenu" anchor="last"/>
        </action>
    </actions>

class 就是真的Class名字,icon是我自己添加的,加個(gè)圖標(biāo)更顯眼,group-id是插件位置,這里是Tools目錄下,最后一個(gè)

回到TinyAction中

 String api = Messages.showInputDialog(project, "請(qǐng)輸入API KEY", "TinyPic", Messages.getQuestionIcon());
        if (TextUtils.isEmpty(api)) {
            return;
        }

會(huì)彈出一個(gè)Dialog,輸入申請(qǐng)的key,點(diǎn)擊確定,返回String,參數(shù)project是個(gè)上下文對(duì)象?context類似的吧。

接下來就要用到TinyPNG這個(gè)網(wǎng)站提供的API了,真正的壓縮功能就是他們提供的 https://tinypng.com/developers/reference/java

還是 項(xiàng)目右擊->Open Module Settings->Libraries->From Maven,
搜索tinify,選擇最新的,下載到項(xiàng)目中。
完全沒Android Studio的Gradle依賴簡(jiǎn)單。
現(xiàn)在就能引用到這個(gè)API了,首先初始化

  Tinify.setKey(api);
FileChooserDescriptor descriptor = new FileChooserDescriptor(true, true, false, false, false, true);
        VirtualFile[] selectedFiles = FileChooser.chooseFiles(descriptor, project, null);
        if (selectedFiles.length == 0) {
            return;
        }

這段代碼會(huì)跳出一個(gè)文件選擇Dialog,注意參數(shù),選擇文件或者文件夾,可以多選。
返回結(jié)果是這個(gè)plugin sdk的VirtualFile類,因?yàn)槭嵌噙x,返回的是個(gè)數(shù)組。這個(gè)VirtualFile可以是文件,或者文件夾,所以下一步很關(guān)鍵了。

    private void filterAllPictures(VirtualFile[] selectedFiles) {
        for (int i = 0; i < selectedFiles.length; i++) {
            VirtualFile selectedFile = selectedFiles[i];
            if (selectedFile.isDirectory()) {
                VirtualFile[] directoryChildren = selectedFile.getChildren();
                filterAllPictures(directoryChildren);
            } else if (selectedFile.getName().endsWith("jpg") || selectedFile.getName().endsWith("png")) {
                logger.info("path=" + selectedFile.getPath());
                pictureFiles.add(selectedFile);
                if (i >= selectedFiles.length - 1) {
                    return;
                }
            }
        }
    }

這段代碼就比較復(fù)雜了啊,功能是篩選出所有的圖片文件,放在ArrayList中。
首先循環(huán)一下,
1.如果是文件夾,獲取這個(gè)文件夾下的所有文件,又可能是文件或文件夾,遞歸
2.如果是文件,判斷文件后綴是不是jpg或png,跳出

接下來新建個(gè)類,繼承自plugin sdk的DialogWraper,就是自定義Dialog了,
功能很簡(jiǎn)單,就是加個(gè)進(jìn)度條和500次使用超出的文字說明

因?yàn)槭荍ava代碼,用的是JavaSE的Swing,有沒有回到上古時(shí)代的感覺。Intelij的IDE全是用Java開發(fā)的,這么惡心的東西。。我也是服了

    @Nullable
    @Override
    protected JComponent createCenterPanel() {
        jPanel = new JPanel();

        jProgressBar = new JProgressBar(SwingConstants.HORIZONTAL, 0, maxImages);
        jProgressBar.setString(currentIndex + "/" + maxImages);
        jProgressBar.setValue(currentIndex);
        jProgressBar.setStringPainted(true);

        reminderText = new JTextArea("每月500張圖片限制已用完,請(qǐng)獲取新KEY");
        reminderText.setVisible(false);
//        reminderText.setForeground(Color.CYAN);
        reminderText.setBackground(new Color(255, 255, 255, 0));

        jPanel.setLayout(new GridLayout(2, 1));
        jPanel.add(jProgressBar);
        jPanel.add(reminderText);
        return jPanel;
    }

重寫這個(gè)方法,就是Dialog里顯示的內(nèi)容。
JPanel就是一個(gè)Layout,添加個(gè)ProgressBar和TextArea,TextArea默認(rèn)不顯示,跟Android還是挺像的

        filterAllPictures(selectedFiles);
        tinyFiles();

        progressDialog = new ProgressDialog(project);
        progressDialog.setTitle("上傳進(jìn)度");
        progressDialog.setMaxImages(pictureFiles.size());
        progressDialog.revalidate();

        progressDialog.show();

先篩選出圖片,然后 tinyFiles()里開線程發(fā)送壓縮圖片的請(qǐng)求,
Dialog的顯示要放在后面。在Plugin里Dialog會(huì)阻塞主線程,如果先顯示Dialog,后面代碼就要在Dialog消失后再執(zhí)行
考慮到前面的代碼,先彈出輸入Key的Dialog,點(diǎn)擊確定之后Tinify初始化
彈出文件選擇Dialog,選擇之后才執(zhí)行篩選圖片代碼。
Android的Dialog雖然會(huì)讓activity pause,但不會(huì)把a(bǔ)ctivity卡住啊,真是坑

    private void tinyFiles() {
        cancelTiny = false;
        for (int i = 0; i < pictureFiles.size(); i++) {
            currentIndex = 0;
            VirtualFile virtualFile = pictureFiles.get(i);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Source source = null;
//                    logger.info("path=" + virtualFile.getPath());
                    try {
                        if (!cancelTiny) {
                            source = Tinify.fromFile(virtualFile.getPath());
                            Result result = source.result();
                            logger.info("result size=" + result.size() + " mediaType=" + result.mediaType() + " " + result.toString());
                            source.toFile(virtualFile.getPath());

                            currentIndex++;
                            progressDialog.setCurrentIndex(currentIndex);
                            progressDialog.revalidate();

                        }
                    } catch (Exception e1) {
//                        logger.warning(e1.toString());
                        e1.printStackTrace();
                        if (e1.toString().contains("AccountException")) {
                            cancelTiny = true;
                            progressDialog.showError();
                        }
                    }
                }
            }).start();
        }
    }

壓縮圖片就簡(jiǎn)單了,這個(gè)api不是異步的,所以要放在新線程里,然后更新下progress,如果報(bào)錯(cuò)了,大概就是500次免費(fèi)次數(shù)到了。

發(fā)布

1.在plugin.xml里填寫信息,版本號(hào)之類的
注意添加depends,如果不添加,這個(gè)插件只能在Intelij和AndroidStudio中使用

    <depends>com.intellij.modules.lang</depends>

Module  Product
com.intellij.modules.java   IntelliJ IDEA
com.intellij.modules.ultimate   IntelliJ IDEA Ultimate Edition
com.intellij.modules.androidstudio  Android Studio
com.intellij.modules.appcode    AppCode
com.intellij.modules.cidr.lang  AppCode, CLion
com.intellij.modules.cidr.debugger  AppCode, CLion, RubyMotion
com.intellij.modules.clion  CLion
com.intellij.modules.database   IntelliJ IDEA Ultimate Edition, PhpStorm, RubyMine, PyCharm, DataGrip
com.intellij.modules.python PyCharm
com.intellij.modules.ruby   RubyMine

這個(gè)是插件兼容性的表,如果用了某些功能,就只能對(duì)應(yīng)IDE使用

2.打包,Build->Prepare Plugin XXX For Deployment 生成Jar包
3.發(fā)布,https://plugins.jetbrains.com/ 登錄,上傳插件,審核一般要兩天

說下感悟:
1.有什么事真的是想做就去做,以前我一直覺得開發(fā)插件挺高端了,但是從零開始開發(fā)一個(gè)這樣簡(jiǎn)單的插件就花了一天時(shí)間。
2.作為一個(gè)Android開發(fā),表示Java學(xué)的真是爛,或者說Android提供了好多方便的api,AsyncTask,Handler之類的。有很多Java基礎(chǔ)的知識(shí)平時(shí)工作中根本遇不到,跟JavaEE同事聊天中發(fā)現(xiàn)他們接觸的很多,我希望過時(shí)的東西慢慢被淘汰,哈哈

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容