大數據

Android Studio Assistant 基礎功能 —— Action

0527banner.jpg
小 M 自從上次發佈了新版 IDEA 插件之後,Assistant 新穎的接入方式收到了一致好評,但是第一版的 Assistant 只有介紹和基礎接入功能,老闆希望小M多加一些功能,比如像 Firebase 接入的時候,有按鈕顯示接入狀態,可以 apply 一些 Gradle 的插件等等功能。


Ⅰ 起源 —— Action

這些肯定難不倒小 M,我們只要參考下 Firebase 的集成就好了。其實我們大部分業務開發都是基於“事件”這個模型的,包括普通的 Web 後端和前端上的開發,IDEA 相關的內容也不例外,IDEA 響應的用戶的動作一般都是 Action,比如點擊菜單裡的某一項,就是響應 AnAction 的操作。比如我們舉個例子,在之前 Assistant 相關的 xml 中,有如下代碼:

<action key="mpaas.integrate_dependencies" label="點擊添加">
  ....
</action>

我們需要對這個 Action 做處理,根據之前 firebase 相關的集成方式,首先需要在 plugin.xml 中註冊如下內容:

<extensions defaultExtensionNs="com.android.tools.idea.assistant">
  <actionHandler implementation="com.alipay.mpaas.assistant.actions.MPIntegrateBaselineActionHandler" />    
</extensions>

在這個類中,複寫getId()方法:

class MPIntegrateBaselineActionHandler: AssistActionHandler {
​
  companion object {
    const val ACTION_KEY = "mpaas.integrate_dependencies"
  }
​
  override fun getId() = ACTION_KEY
}

這樣就和上面 xml 中的內容對應上了,它提供了一個 handlAction 方法,我們可以在這裡寫邏輯:

override fun handleAction(actionData: ActionData, project: Project) {
    ....
  }

那這裡就是小助手和我們代碼連接的地方了,經過以上的說明,對於響應事件這件事,我們就已經做完了。


Ⅱ 操作 Gradle 文件

第二步,就是操作 Gradle 文件了。IDEA 插件裡面其實沒有內置 Gradle 引擎(顯然也不合算),但是它通過 Psi 提供了對 Gradle DSL 解析的弱支持(不是完整支持)。同時提供了一些語義化的模型來簡化這個問題。
我們注意到 Android Studio 提供了這麼一個類 GradleBuildModel 在 Anroid Studio 3.6 中,它提供的接口如下:
640.png
看 android / buildscript / dependencies / ext 我們馬上可以知道,這裡對應我們 build.gradle 中幾個 DSL 的 block,比如我們需要往 buildscript 中加入特定的 maven,用來拉取 sdk 或者 gradle 插件的話,那麼按如下方式操作:

① 獲取與修改 GradleBuildModel

GradleModelProvider.get().getBuildModel(project)
    //or
GradleModelProvider.get().getBuildModel(module)

GradleBuildModel 一般是在 sync 完成之後,會被 AS 緩存起來,我們能以 O(1) 的效率去獲取,然後我們這邊還是以 buildscript 為例,它對應 BuildScriptModel,在 build.gradle 中的內容如下:

buildscript {
    ext.mpaas_artifact = "mpaas-baseline"
    ext.mpaas_baseline = "10.1.68-5"
    repositories {
        mavenCentral()
        jcenter()
        google()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.6.3'
    }
}

那麼我們往repositories添加一個阿里雲的 maven 倉庫的方式就很簡單了,我們調用RepositoriesModeladdMavenRepositoryByUrl方法。

repositoriesModel.addMavenRepositoryByUrl("https://maven.aliyun.com/repository/central")

② 回寫 GradleBuildModel

這一步改完後,在 BuildModel 就暫存了剛剛的內容,我們還需要把這塊內容回寫回去:

WriteCommandAction.runWriteCommandAction(project, buildModel::applyChanges)

最終實現效果如下:
20200528143338130.png

③ 添加複雜 Maven DSL 表達式

當然,上面視頻裡面展示的效果是添加一個比較複雜的 maven 配置,有 name / credential 等配置,因為 RepositoriesModel 只給我們提供了添加 url 一種方式,如果想實現以上的效果,我們需要使用反射的方式,操作 GradleDslBlockModel 的方式來進行。

val myDslElementField = GradleDslBlockModel::class.java.getDeclaredField("myDslElement")
myDslElementField.isAccessible = true

val myDslElement: GradlePropertiesDslElement = myDslElementField.get(repositoryModel) as GradlePropertiesDslElement

val nameElement = GradleNameElement.create("maven")
val mavenDslElement = MavenRepositoryDslElement(myDslElement, nameElement)
val mavenCredentialsDslElement = MavenCredentialsDslElement(mavenDslElement)

mavenCredentialsDslElement.setNewLiteral("username", "xxx")
mavenCredentialsDslElement.setNewLiteral("password", "xxx")

mavenDslElement.setNewLiteral("url", ALIPAY_MAVEN_URL)
mavenDslElement.setNewLiteral("name", "alipay")

mavenDslElement.addParsedElement(mavenCredentialsDslElement)
myDslElement.setNewElement(mavenDslElement)

完成以上的工作,我們就能通過 Action 的方式操作 Gradle 文件了。


Ⅲ 狀態管理

點完這個按鈕後,如果能有一個提示來告訴用戶是否接入成功,這簡直就太好啦:
640 (1).png
這需要一個叫 ActionStateManager 的組件

<extensions defaultExtensionNs="com.android.tools.idea.assistant">
  <actionStateManager implementation="com.alipay.mpaas.assistant.actions.MPIntegrateBaselineStateManager" />
</extensions>

我們同時也來寫一個這樣的組件,它繼承於 AssistActionStateManager 裡面有幾個類需要複寫
640 (2).png
這裡的 getId() 返回你剛剛註冊 Action 的那個 id 即可,我這裡就是 mpaas.integrate_dependencies 這裡我們 getState() 支持返回的狀態有這麼幾種可以選:
640 (3).png
當然,你也可以根據提示自己新建一種狀態,按照這個枚舉的名字,和裡面參數的定義,我們能知道每一種狀態代表的含義。
因為這個類的生命週期沒有相關的回調,如果我們需要這個類的實例,因此我們需要在 AS 調用 init 方法的時候,自己拿到它的實例存起來。


前情回顧.png

介紹一位不太熟的老友:Android Studio Assistant

作者名片.jpg
動態-logo.gif
公眾號媒體導流矩陣.jpg

Leave a Reply

Your email address will not be published. Required fields are marked *