Android Studio插件開發(fā)3之Extensions And Extension Points(擴(kuò)展與擴(kuò)展點(diǎn))

插件開發(fā)系列
Android Studio插件開發(fā)1之插件介紹與環(huán)境搭建
Android Studio插件開發(fā)2之Action System
Android Studio插件開發(fā)3之Extensions And Extension Points(擴(kuò)展與擴(kuò)展點(diǎn))

如果說(shuō)自己定義Action并實(shí)現(xiàn)相應(yīng)的功能邏輯是造輪子的話,那么實(shí)現(xiàn)Extensions就是使用別人的輪子了,簡(jiǎn)單快速實(shí)現(xiàn)復(fù)雜的功能!

定義

Extensions 和Extension Points是Intellij平臺(tái)提供的一套供插件之間或者是插件與平臺(tái)核心功能之間通信的接口。

Extension points

一個(gè)插件提供給其它插件擴(kuò)展自己功能的入口點(diǎn),通過定義接口來(lái)約定溝通的方法,通俗點(diǎn)說(shuō)就是造好輪子等別人來(lái)用。

Extensions

一個(gè)插件聲明一個(gè)Extension,并通過對(duì)應(yīng)的Extension Point實(shí)現(xiàn)相應(yīng)的功能,通俗的說(shuō)就是復(fù)用別人造好的輪子。

關(guān)系圖

如果文字表達(dá)得不夠明白,看一下以下的說(shuō)明圖應(yīng)該能加深理解,畢竟一圖勝千言

說(shuō)明圖.png

聲明Extension和Extension Point

Extension和Extension Point都需要在plugin.xml聲明,聲明的語(yǔ)法如下

Extension Point

<extensionPoints>
  <extensionPoint name="ConcreteExtensionPoint1" beanClass="com.example.BeanClass">
  <extensionPoint name="ConcreteExtensionPoint2" interface="com.example.Interface">
</extensionPoints>
  • name 此Extension Point的名字
  • beanClass/interface 提供的接口,定義與Extension的交互方式

Extension Point聲明的方式有兩種,第一是通過interface的方式,此方式定義一個(gè)java接口供擴(kuò)展方實(shí)現(xiàn);第二是beanClass的方式,其定義一個(gè)java bean,并在擴(kuò)展方聲明Extension的時(shí)候,由擴(kuò)展方提供java bean的屬性,這里不明白的話先看下面Extension的聲明。

Extension

聲明通過interface方式定義的Extension

<extensions defaultExtensionNs="com.intellij">
    <appStarter implementation="MyTestPackage.MyTestExtension1" />
</extensions>

Extesion的聲明應(yīng)該被包裹在<extensions>標(biāo)簽下

  • <extensions>標(biāo)簽的defaultExtensionNs屬性的值是對(duì)應(yīng)Extension Point的插件id,但如果這個(gè)Extension Point由Intellij提供,則是“com.intellij”,插件的id可以在plugin.xml文件查看
  • 其中的標(biāo)簽的名字是Extension Point的name,例如要用到上面聲明的Extension Point,則是<ConcreteExtensionPoint1>

這里內(nèi)容很簡(jiǎn)單,就是實(shí)現(xiàn)接口,通過implementation屬性提供接口

聲明通過beanClass方式定義的Extension

<extensions defaultExtensionNs="com.intellij">
    <codeInsight.template.postfixTemplateProvider language="JAVA" implementationClass="com.kogitune.intellij.codeinsight.postfix.AndroidPostfixTemplateProvider"/>
</extensions>

這里language和implementationClass實(shí)際上是java bean的屬性,下面是這個(gè)Extension Point的beanClass的內(nèi)容

public class LanguageExtensionPoint<T> extends CustomLoadingExtensionPointBean implements KeyedLazyInstance<T> {

  // these must be public for scrambling compatibility
  @Attribute("language")
  public String language;

  @Attribute("implementationClass")
  public String implementationClass;

  private final NotNullLazyValue<T> myHandler = new NotNullLazyValue<T>() {
    @Override
    @NotNull
    protected T compute() {
      try {
        return (T)instantiateExtension(implementationClass, ApplicationManager.getApplication().getPicoContainer());
      }
      catch (ClassNotFoundException e) {
        throw new RuntimeException(e);
      }
    }
  };

  @NotNull
  @Override
  public T getInstance() {
    return myHandler.getValue();
  }

  @Override
  public String getKey() {
    return language;
  }
}

其中l(wèi)anguage和implementationClass上加了@Attribute注解,加了這個(gè)注解的屬性需要由Extension在聲明時(shí)提供

<codeInsight.template.postfixTemplateProvider language="JAVA" implementationClass="com.kogitune.intellij.codeinsight.postfix.AndroidPostfixTemplateProvider"/>

實(shí)例

一般情況下都是我們寫的都是功能比較簡(jiǎn)單的小插件,除非是專門寫插件的軟件公司,否則很少情況下會(huì)在插件里定義Extension Point供別人使用,所以重點(diǎn)是怎樣使用別人的Extension Point,尤其是系統(tǒng)提供的Extension Point,那可是系統(tǒng)的核心功能。(好吧是其實(shí)我不會(huì)寫Extension Point(-_-))

通過Extension可以做什么?

先看三張圖

annotate.png
livetemplate.gif
postfixcompletion.gif

第一張圖是代碼編輯器的錯(cuò)誤提示,第二張圖是live template,第三張圖是系統(tǒng)提供的postfix completion,相信這些功能我們平時(shí)都不少用,其實(shí)這些功能我們都可以通過Extension來(lái)自定義的!

這里提供一個(gè)livetemplate的實(shí)例和推薦一個(gè)postfix completion的項(xiàng)目

live template

想當(dāng)年Eclipse用得飛起的時(shí)候“syso”打印字符串到控制臺(tái)的代碼補(bǔ)全用得非常順手,剛轉(zhuǎn)到Intellij平臺(tái)的時(shí)候還有點(diǎn)不適應(yīng)呢,現(xiàn)在借助live template我們也能實(shí)現(xiàn)一個(gè)Intellij版本的“syso”補(bǔ)全

首先,找到Extension Point,這里的Extension Point是系統(tǒng)提供的defaultLiveTemplatesProvider,這樣我們可以在plugin.xml中聲明我們的Extension

<extensions defaultExtensionNs="com.intellij">
        <!-- Add your extensions here -->
        <defaultLiveTemplatesProvider implementation="MyTemplateProvider"/>
    </extensions>

這個(gè)Extension Point是通過interface聲明的,所以提供實(shí)現(xiàn)類MyTemplateProvider如下

import com.intellij.codeInsight.template.impl.DefaultLiveTemplatesProvider;
import org.jetbrains.annotations.Nullable;

public class MyTemplateProvider implements DefaultLiveTemplatesProvider {

    @Override
    public String[] getDefaultLiveTemplateFiles() {
        return new String[]{"templates/mytemplatefile"};
    }

    @Nullable
    @Override
    public String[] getHiddenLiveTemplateFiles() {
        return new String[0];
    }
}

內(nèi)容很簡(jiǎn)單,就是返回一個(gè)文件的路徑,是相對(duì)于resources文件夾的相對(duì)路徑,不要后綴名,絕對(duì)路徑是 projectpath/resources/templates/mytemplatefile.xml

也就是說(shuō)我們只要在這個(gè)文件里按語(yǔ)法定義好live template就好了,重點(diǎn)也是在定義live template上,mytemplatefile.xml的內(nèi)容如下

<templateSet group="other">
    <template name="syso" value="System.out.println($END$);"
              description="Prints a string to System.out like Eclipse"
              toReformat="false" toShortenFQNames="true">
        <context>
            <option name="JAVA_STATEMENT" value="true"/>
        </context>
    </template>
</templateSet>

一個(gè)<template>標(biāo)簽定義一個(gè)live template,name屬性和value屬性就是livetemplate的縮寫和縮寫展開對(duì)應(yīng)的內(nèi)容,這里只展示實(shí)現(xiàn)Extension的邏輯,具體怎樣自定義live template可以參考相關(guān)文檔
https://www.jetbrains.com/help/idea/live-templates.html

下面是這個(gè)小demo的運(yùn)行效果

customlivetemplate.gif

postfix completion

Android Studio和IDEA提供了一部分postfix completion,可惜的是并沒有提過我們?cè)贗DE里自定義postfix completion的入口,但是可以通過插件增加自己的postfix completion,其原理也是利用系統(tǒng)的Extension Point

有興趣的朋友可以看看這個(gè)我參與的插件項(xiàng)目

android-postfix-plugin

其中用到的Extension Point是codeInsight.template.postfixTemplateProvider

問答

  • 系統(tǒng)有那么多的功能,我怎么知道它有沒有Extension Point或者它的Extension Point是什么?

    不用擔(dān)心,Intellij的文檔提供了下面的Extension Point列表

  • 有Extension Point,但是不會(huì)用怎么辦?

    查看其他插件的源碼,例如那些提供智能補(bǔ)全的插件,都是通過系統(tǒng)的Extension Point完成的,所以可以推測(cè)一下自己常用的插件里有沒有自己需要使用的Extension Point來(lái)學(xué)習(xí)怎樣使用

最后編輯于
?著作權(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)容