您当前的位置: 首页 >  android
  • 0浏览

    0关注

    674博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Android插件编写入门

沙漠一只雕得儿得儿 发布时间:2020-02-09 09:56:06 ,浏览量:0

Gradle Plugin

本质就是把独立的和业务代码无关的,各个项目、子项目通用的逻辑抽离出来进行封装。今天我们从零开始,从最简单的Demo逐渐深入,来演示下gradle的插件如何编写。

入门Demo:最简单的plugin之打印Hello World

首先我们写一个最简单的Android gradle plugin,就在我们APP module,主module的gradle文件里写一个打印helloWorld的插件,非常简单,如下所示:

class PluginDemo implements Plugin {
    @Override
    void apply(Project target) {
        println "Hello plugin"
    }
}

apply plugin: PluginDemo

实现了Plugin接口,实现apply方法即可,然后我们make下项目,就可以看到Hello plugin的打印了。在print里面我们是写死的字符串,改成变量的写法如下:

class PluginDemo implements Plugin {
    @Override
    void apply(Project target) {
        def extension = target.extensions.create('buder', ExtensionDemo)
        target.afterEvaluate {
            println "watch ${extension.name}"
        }
    }
}

class ExtensionDemo {
    def name = '庆余年'
}

apply plugin: PluginDemo

但是这么写是无法动态配置的,例如我们gradle配置的Android版本之类的信息是可以手动填写,可以自己动态配置的:

android {
    compileSdkVersion 28
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.example.plugin"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
升级demo:可以像上面versionCode "1"、versionName "1.0"这样可配置的插件写法 步骤一:在项目中创建一个新的module,可以选择一个java module,这个module的名字必须是buildSrc; 步骤二:然后在main目录下面创建一个resources的文件夹,里面再创建一个META-INF的文件夹,里面再创建一个gradle-plugins的文件夹,最后创建一个xxx.properties的文件(xxx文件名可以随意取);再新建groovy目录用于编写插件逻辑,最终如下图:

上面module以及resources目录的创建就是我们编写插件的基础,其实做法很简单,就是需要创建一个符合Android studio可以为我们编译为插件的一个目录结构,只是这个目录结构需要我们自己创建罢了,要是哪天AS可以支持创建项目或者创建module那样一键创建的话,这两个步骤就不需要我们自己手动创建了。下面我们要做的事就是把刚刚那个入门demo的代码,拆分到不同文件中,而非直接写在主工程的build.gradle文件内。

步骤三:拆分到升级demo的PluginDemo.groovy 以及 ExtensionDemo.groovy中

1.在代码目录下com.example.plugindemo,新建一个PluginDemo.groovy的文件,

class PluginDemo implements Plugin{

    @Override
    void apply(Project project) {
        def extension = project.extensions.create('plugindemo', ExtensionDemo)
        project.afterEvaluate {
            println "watch ${extension.name}"
        }
    }
}

这里注意:第一个参数是xxx.properties文件的文件名称

2.在代码目录下com.example.plugindemo,新建一个ExtensionDemo.groovy的文件,

class ExtensionDemo {
    def name = "kkkk"
}

3.在resources/META-INF/gradle-plugins目录下,新建一个plugindemo.properties的文件,

implementation-class=com.example.plugindemo.PluginDemo

 4.在主工程就是app工程的build.gradle文件中使用,

apply plugin: 'plugindemo'

plugindemo {
    name '《新世界》'
}

这里注意:这里的plugindemo就是之前的xxx.properties的文件名,这里起的是PluginDemo,这个名字可以随意起,但是一定要和xxx.properties的文件名保持一致。

上面的1--3步就是将原来入门demo的那几行代码拆分到Android studio所能识别到的文件中去,步骤4就是使用,达到和我们使用versionName "1.0" 一样的效果,make项目后就可以打印出:watch 《新世界》。

上述过程的工程目录:

需要注意的几点:

1.plugindemo.properties里面的值就是PluginDemo.groovy的类的全限定名,

2.plugindemo.properties这个文件的文件名是可以随便起的,比如您起为abcd.properties

3.resources/META-INF/gradle-plugins/*.properties 中的 * 是插件的名称,例如*.properties 是 abcd.properties,最终在应用插件时的代码就是 apply plugin: 'abcd',在使用的时候,下面的就是您的这个properties的文件名必须保持一致

apply plugin: 'abcd'

abcd {
    name '新世界'
}

而且注意,PluginDemo.groovy中的extension创建函数里的第一个参数也是abcd,

def extension = project.extensions.create('plugindemo', ExtensionDemo)

4.关于 buildSrc ⽬目录

  • 这是 gradle 的⼀一个特殊⽬目录,这个⽬目录的 build.gradle 会⾃自动被执⾏行行,即使不不配配置进settings.gradle
  • buildSrc 的执⾏行行早于任何⼀一个 project,也早于 settings.gradle。它是⼀一个独⽴立的存在
  • buildSrc 所配置出来的 Plugin 会被⾃自动添加到编译过程中的每⼀一个 project 的 classpath,因此它们才可以直接使⽤用 apply plugin: 'xxx' 的⽅方式来便便捷应⽤用这些 plugin
  • settings.gradle 中如果配置了了 ':buildSrc' ,buildSrc ⽬目录就会被当做是⼦子 Project ,因此会被执⾏行行两遍。所以在 settings.gradle ⾥里里⾯面应该删掉 ':buildSrc' 的配置
添加Transform的Demo:

transform是什么:Transform是由 Android 提供的,在项⽬目构建过程中把编译后的⽂文件(jar ⽂文件和 class ⽂文件)添加自定义的中间处理过程的工具

步骤一:因为需要编写gradle代码,所以在buildSrc项目的gradle文件中需要加入依赖,才能使用gradle相关的API
repositories {
    google()
    jcenter()
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.tools.build:gradle:3.5.3'
}
步骤二:将之前的自定义的apply plugin放到后面,因为你添加transform,它的初始化太靠前了,否则会报错:
android {
    compileSdkVersion 28
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.example.plugin"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

apply plugin: 'plugindemo'

plugindemo {
    name '新世界'
}

dependencies {
步骤三:编写TransformDemo.groovy文件:
package com.example.plugindemo

import com.android.build.api.transform.QualifiedContent
import com.android.build.api.transform.Transform
import com.android.build.api.transform.TransformException
import com.android.build.api.transform.TransformInvocation
import com.android.build.gradle.internal.pipeline.TransformManager;

public class TransformDemo extends Transform{

    /**
     * 所添加的task名称
     * @return
     */
    @Override
    String getName() {
        return "buderTransform"
    }

    /**
     * 可以改class文件、jar包、资源文件等
     * 这里我们要是需要修改字节码,就为 TransformManager.CONTENT_CLASS
     * @return
     */
    @Override
    Set getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    /**
     * 修改的范围
     * 这里为整个项目范围
     * @return
     */
    @Override
    Set            
关注
打赏
1657159701
查看更多评论
0.0640s