天天看点

Android Studio Assistant 基础功能 —— ActionⅠ 起源 —— ActionⅡ 操作 Gradle 文件Ⅲ 状态管理

Android Studio Assistant 基础功能 —— ActionⅠ 起源 —— ActionⅡ 操作 Gradle 文件Ⅲ 状态管理

小 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 中,它提供的接口如下:

Android Studio Assistant 基础功能 —— ActionⅠ 起源 —— ActionⅡ 操作 Gradle 文件Ⅲ 状态管理

看 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 仓库的方式就很简单了,我们调用

RepositoriesModel

addMavenRepositoryByUrl

方法。

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

② 回写 GradleBuildModel

这一步改完后,在 BuildModel 就暂存了刚刚的内容,我们还需要把这块内容回写回去:

WriteCommandAction.runWriteCommandAction(project, buildModel::applyChanges)           

最终实现效果如下:

Android Studio Assistant 基础功能 —— ActionⅠ 起源 —— ActionⅡ 操作 Gradle 文件Ⅲ 状态管理

③ 添加复杂 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 文件了。

Ⅲ 状态管理

点完这个按钮后,如果能有一个提示来告诉用户是否接入成功,这简直就太好啦:

Android Studio Assistant 基础功能 —— ActionⅠ 起源 —— ActionⅡ 操作 Gradle 文件Ⅲ 状态管理

这需要一个叫 ActionStateManager 的组件

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

我们同时也来写一个这样的组件,它继承于 AssistActionStateManager 里面有几个类需要复写

Android Studio Assistant 基础功能 —— ActionⅠ 起源 —— ActionⅡ 操作 Gradle 文件Ⅲ 状态管理

这里的 getId() 返回你刚刚注册 Action 的那个 id 即可,我这里就是 mpaas.integrate_dependencies 这里我们 getState() 支持返回的状态有这么几种可以选:

Android Studio Assistant 基础功能 —— ActionⅠ 起源 —— ActionⅡ 操作 Gradle 文件Ⅲ 状态管理

当然,你也可以根据提示自己新建一种状态,按照这个枚举的名字,和里面参数的定义,我们能知道每一种状态代表的含义。

因为这个类的生命周期没有相关的回调,如果我们需要这个类的实例,因此我们需要在 AS 调用 init 方法的时候,自己拿到它的实例存起来。

Android Studio Assistant 基础功能 —— ActionⅠ 起源 —— ActionⅡ 操作 Gradle 文件Ⅲ 状态管理

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

Android Studio Assistant 基础功能 —— ActionⅠ 起源 —— ActionⅡ 操作 Gradle 文件Ⅲ 状态管理
Android Studio Assistant 基础功能 —— ActionⅠ 起源 —— ActionⅡ 操作 Gradle 文件Ⅲ 状态管理
Android Studio Assistant 基础功能 —— ActionⅠ 起源 —— ActionⅡ 操作 Gradle 文件Ⅲ 状态管理

继续阅读