Gradle 插件入门

    xiaoxiao2021-03-25  49

    Android使用gradle来打包应用越来越普遍了,gradle打包的形式越来越多样化了。butterknife自定义了插件用来生成R2文件。tinker自定义了插件来生成diff。写一个插件可以更加清晰的看到自己打包的流程,同时写好一个插件也需要对打包的流程非常的熟悉。当然这篇文章没有这么的高深,简单的介绍怎么自定义一个插件以及一些简单的打包命令和配置。插件可以做的事情确实太多了。

    自定义Gradle Plugin

    新建一个java library module。 apply plugin: 'java' apply plugin: 'groovy' // gradle library dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile gradleApi() } sourceCompatibility = "1.7" targetCompatibility = "1.7" group='com.egos.gradle.plugins' name='pluginsample' version='0.0.1' 新建一个类(.groovy)继承Plugin,那么一个简单的插件就定义好了。 // 需要创建新的文件夹groovy,将.groovy文件放在里面 package com.egos.gradle.plugins; class SamplePlugin implements Plugin<Project> { protected final Logger log = Logging.getLogger(getClass()); void apply(Project project) { println 'This is a sample plugin.' } } 创建.properties用来指定插件实现类,并发布的在本地(可以调用gradle uploadArchives将plugin发布在本地)。在main目录下面创建resources/META-INF.gradle-plugins/com.egos.gradle.properties。 # 最后使用的时候需要com.egos.gradle。 implementation-class=com.egos.gradle.plugins. SamplePlugin

    执行gradle uploadArchives就会发布在本地仓库。

    apply plugin: 'maven' group='com.egos.gradle.plugins' name='pluginsample' version='0.0.1' uploadArchives { repositories { mavenDeployer { repository(url: uri('../repo')) } } } 使用Gradle Plugin。可以在全局使用(根目录下build.gradle),或者某个module使用。配置完成以后执行打包的时候就可以看到This is a sample plugin.的输出。 buildscript { repositories { // 指定仓库地址 // jcenter() // 如果上传到jcenter的话 maven { // 本例中上传到了本地的maven中。 url uri('../repo') } } dependencies { classpath 'com.egos.gradle.plugins: pluginsample:0.0.1' // 也可以直接指定jar文件的地址使用的,但是无法调试 // classpath fileTree(dir:'../pluginsample/build/libs', include: ['*.jar']) } } apply plugin: 'com.egos.gradle' 高级用法。从上面简单的Demo来看没有任何实际的作用,下面就来一些例子。

    (1) 将build.gradle中的代码移到plugin中。作用还是一样的,但是方便调试以及方便书写(build.gradle不能调试,个人感觉效率比较低)。还有如果需要的操作过于复杂,例如生成文件等的时候,写在build.gradle中就更加不方便。

    // 在上面SamplePlugin的apply中加入如下代码。 project.afterEvaluate { //找到preDebugBuild任务,然后添加一个Action project.tasks.getByName("preDebugBuild") { it.doFirst { println "preDebugBuild doFirst" } } }

    (2) 定义高级方法。最前面有介绍Tinker可以使用gradle来生成diff。同样的,方便调试以及测试。

    调试Gradle Plugin

    上面一直在说调试插件,那么插件该如何调试呢?这个问题困扰过自己,一直以来都是通过jar包路径来指定插件的路径的,每次都是通过输出Log信息来查看,找到了一个方法(下文参考中的文章Intellij / Android Studio 调试 Gradle Plugin)。这里也写一下部分内容,其它可以参考上面博客。

    首先需要完成上面使用Gradle Plugin操作指定插件地址。如果指定的事远程仓库或者jar地址就无法调试了。 buildscript { repositories { maven { // 本例中上传到了本地的maven中。 url uri('../repo') } } dependencies { classpath 'com.egos.gradle.plugins: pluginsample:0.0.1' } apply plugin: 'com.egos.gradle' 选择需要调试的内容。 // 在terminal中输入下面代码。这里的gradlew assembleDebug可以自行选择,也可以是gradle assembleDebug gradlew assembleDebug -Dorg.gradle.daemon=false -Dorg.gradle.debug=true

    常用gradle命令

    gradle tasks // 获取task信息 gradle dependencies // 获取以来关系 gradle assembleDebug // 打包Debug gradle :app:tasks // app(module名字)可以用来区分是哪个module的。每一个任务都可以这样区分。 gradle lint // lint检查

    build.gradle常用的配置

    sourceSets:配置文件目录 android{ sourceSets { main { // 主工程的文件配置 manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] jniLibs.srcDirs = ['libs'] } test { // 主工程java文件配置 java.srcDirs = ['test/java'] } xxFlavor { // 某个flavor的文件配置(在Build Variant 切换到相应的flavor的时候就会默认使用那个flavor的代码) manifest.srcFile 'xxFlovar/AndroidManifest.xml' java.srcDirs = ['xxFlovar/java'] res.srcDirs = ['xxFlovar/res'] } } productFlavors:配置不同包 android { deft{} // 默认包 removeAd{} // 没有广告的包 ...etc } signingConfigs:签名配置 adroid { signingConfigs { config { storeFile "key.store" storePassword "key.store.password" keyAlias "key.alias" keyPassword "key.alias.password" } } } buildTypes:不同打包方式配置 android { buildTypes { haha { // 这里其实是可以任意配置的,比如我配置haha,只是默认会有debug和release minifyEnabled true } debug { signingConfig signingConfigs.config } release { // 替换Manifest文件中的渠道号 manifestPlaceholders = [UMENG_CHANNEL_VALUE: "umeng_xx"] minifyEnabled true // 混淆开关 signingConfig signingConfigs.config // 签名配置 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' // 混淆文件配置 } } } // 替换Manifest文件中的渠道号,类似友盟等等的会在AndroidManifext.xml中配置友盟的一些信息 <meta-data android:name="UMENG_CHANNEL" android:value="umeng_${UMENG_CHANNEL_VALUE}"/> // manifestPlaceholders会改掉 applicationVariants android { applicationVariants.all { variant -> } } 一些其它重要配置 android { defaultConfig { multiDexEnabled true // 开启分dex } lintOptions { // 一般会设置false,lint检查出错不提示 abortOnError false } dexOptions { incremental false preDexLibraries = false jumboMode = true } packagingOptions { exclude 'META-INF/LICENSE.txt' // 打包时去掉一些内容 exclude 'META-INF/NOTICE.txt' } ndk { abiFilters 'armeabi' // 过滤ndk的信息,比如这里只会打arm版本的so文件 } }

    配置编译信息

    gradle build 配置信息。例如:gradle build -xx -yy。实际使用的时候需要套一个模版。gradle build -Pxx=xx -Pyy=yy -Pxx是固定的模版/build.gradle中Properties()相当于里面的属性、Project(org.gradle.api.Project,相当于一个工程)。可以在android–defaultConfig–下面配置buildConfigField信息。

    // build.gradle文件 // gradle build -Phaha="哈哈" Properties buildProperties = new Properties(); buildProperties.put("haha", "你好"); // 配置默认的信息 // 获取配置的haha属性 if(project.hasProperty("haha")){ buildProperties.put("haha",project.property("haha")) } android { defaultConfig { // 写入到BuildConfig中。 buildConfigField("String", "haha", "\"" +buildProperties.get("haha") + "\"") } }

    思考

    想起最开始在2015工程代码从Eclipse迁入到AS的时候,感觉build.gradle是一个很神秘的东西,后来接触了一些插件,自己也写过一些(打包完成以后输出到指定的文件夹等)到现在看源码的时候,很多库都有通过groovy写一些自己的插件。build.gradle不再是一个神秘的东西并且随着配置原来越多、项目越来越大发现它显得太过于臃肿(可能不是源码级别的文件,看起来总是觉得臃肿)。或许将一些比较复杂的任务从build.gradle中脱离处理,写成一个插件是一种更好的解决方案,方便调试,也方便复用。

    问题

    怎么打纯净版的apk? 实际的项目中总是会有多个flavor,并且可能打包出来的代码有些不一样,比如一个默认包,一个去广告包,但是可以会用初始化的操作,如何打包的时候将这些初始化的操作都去掉呢?

    参考

    自定义Gradle插件 Intellij / Android Studio 调试 Gradle Plugin Android官方技术文档翻译——Gradle 插件用户指南(7)

    转载请注明原文地址: https://ju.6miu.com/read-27419.html

    最新回复(0)