Android Sutdio ( Intellij ) 插件开发

先给代码:
https://github.com/shenjiajun53/TinyPic 喜欢请给个star

TinyPic 介绍

一个Intellij的插件,不仅仅是在Android Studio中使用,可以在所有Jetbrains的IDE中使用
功能:压缩图片资源,一次最多压缩500张
压缩的核心功能是TinyPng这个网站提供的

https://tinypng.com/

但是这个网站一次只能上传20张图片,所以你需要上传下载,上传下载重复工作。
好在这个网站提供了api可以压缩图片。

在开发者页面下申请api key。对于一个key,每月有500次的免费压缩额度,如果压缩超过了
500张图片,就不能使用了。需要另外付费。但是申请这个api特别简单,填下邮箱,用户名就行,多申请
两个邮箱。1000张图片也妥妥够了。
这里推荐google个十分钟邮箱,不需要注册,只能使用十分钟,用来收一下验证码很方便

tinypng_develop.png

使用方式

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

2.安装完后重启,在Tools目录下找到TinyPic

location.png

3.输入在 https://tinypng.com/developers 申请的api key

input_key.png

4.选择图片,可以选择图片,或者选择文件夹或者同时选中,反正是遍历文件夹下的图片,筛选jpg和png
,key的剩余次数

select_images.png

5.压缩进度

progress.png

6.超过500次的提示(后续会考虑加入 生成压缩的信息的文件,因为大家都用git,其实也不是很必要)

warning.png

为什么做这个插件

之前在做apk瘦身的时候考虑到,相比代码,图片才是占了更多大小,减少图片大小有两步。
1.用Android Studio的lint工具,自动删除没有引用的资源,这一步需要注意,有些名字是拼接起来的资源也可能被删除。
2.压缩图片,但是考虑到没有好用的工具,我决定自己开发个插件

下面是开发过程

http://www.jetbrains.org/intellij/sdk/docs/index.html 这个是官方文档

这是我看过的最烂的文档之一,但是Intellij插件开发这方面文档很少,将就着看吧

1.下载Intellij社区版,社区版是免费的,而且调试插件更方便,所以推荐这个

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

2.new project 选择 Plugin

new_project.png

3.项目右击->Open Module Settings->SDKs 选择Intellij安装目录

add_sdk.png

4.添加action,这个action其实就是个用户操作的事件,比如说点击按钮,
需要填几个信息,Id,Name,插件位置

add_action.png

创建完之后生成了一个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是我自己添加的,加个图标更显眼,group-id是插件位置,这里是Tools目录下,最后一个

回到TinyAction中

 String api = Messages.showInputDialog(project, "请输入API KEY", "TinyPic", Messages.getQuestionIcon());
        if (TextUtils.isEmpty(api)) {
            return;
        }

会弹出一个Dialog,输入申请的key,点击确定,返回String,参数project是个上下文对象?context类似的吧。

接下来就要用到TinyPNG这个网站提供的API了,真正的压缩功能就是他们提供的 https://tinypng.com/developers/reference/java

还是 项目右击->Open Module Settings->Libraries->From Maven,
搜索tinify,选择最新的,下载到项目中。
完全没Android Studio的Gradle依赖简单。
现在就能引用到这个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;
        }

这段代码会跳出一个文件选择Dialog,注意参数,选择文件或者文件夹,可以多选。
返回结果是这个plugin sdk的VirtualFile类,因为是多选,返回的是个数组。这个VirtualFile可以是文件,或者文件夹,所以下一步很关键了。

    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;
                }
            }
        }
    }

这段代码就比较复杂了啊,功能是筛选出所有的图片文件,放在ArrayList中。
首先循环一下,
1.如果是文件夹,获取这个文件夹下的所有文件,又可能是文件或文件夹,递归
2.如果是文件,判断文件后缀是不是jpg或png,跳出

接下来新建个类,继承自plugin sdk的DialogWraper,就是自定义Dialog了,
功能很简单,就是加个进度条和500次使用超出的文字说明

因为是Java代码,用的是JavaSE的Swing,有没有回到上古时代的感觉。Intelij的IDE全是用Java开发的,这么恶心的东西。。我也是服了

    @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张图片限制已用完,请获取新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;
    }

重写这个方法,就是Dialog里显示的内容。
JPanel就是一个Layout,添加个ProgressBar和TextArea,TextArea默认不显示,跟Android还是挺像的

        filterAllPictures(selectedFiles);
        tinyFiles();

        progressDialog = new ProgressDialog(project);
        progressDialog.setTitle("上传进度");
        progressDialog.setMaxImages(pictureFiles.size());
        progressDialog.revalidate();

        progressDialog.show();

先筛选出图片,然后 tinyFiles()里开线程发送压缩图片的请求,
Dialog的显示要放在后面。在Plugin里Dialog会阻塞主线程,如果先显示Dialog,后面代码就要在Dialog消失后再执行
考虑到前面的代码,先弹出输入Key的Dialog,点击确定之后Tinify初始化
弹出文件选择Dialog,选择之后才执行筛选图片代码。
Android的Dialog虽然会让activity pause,但不会把activity卡住啊,真是坑

    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();
        }
    }

压缩图片就简单了,这个api不是异步的,所以要放在新线程里,然后更新下progress,如果报错了,大概就是500次免费次数到了。

发布

1.在plugin.xml里填写信息,版本号之类的
注意添加depends,如果不添加,这个插件只能在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

这个是插件兼容性的表,如果用了某些功能,就只能对应IDE使用

2.打包,Build->Prepare Plugin XXX For Deployment 生成Jar包
3.发布,https://plugins.jetbrains.com/ 登录,上传插件,审核一般要两天

说下感悟:
1.有什么事真的是想做就去做,以前我一直觉得开发插件挺高端了,但是从零开始开发一个这样简单的插件就花了一天时间。
2.作为一个Android开发,表示Java学的真是烂,或者说Android提供了好多方便的api,AsyncTask,Handler之类的。有很多Java基础的知识平时工作中根本遇不到,跟JavaEE同事聊天中发现他们接触的很多,我希望过时的东西慢慢被淘汰,哈哈

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容