Android进阶-Gradle

参考链接

Gradle 基础必知必会,一篇带你搞定
Gradle 爬坑指南 – 导论

百度App技术 - Gradle 与 Android 构建入门

Android Gradle (一)Gradle的Android插件入门
Android Gradle (二)签名配置和依赖管理

补齐Android技能树「Gradle篇」专栏

哪怕不学Gradle,这些常见操作,你也得掌握吧
在这里插入图片描述

Gradle是一个框架,作为框架,它负责定义流程和规则。而具体的编译工作则是通过插件的方式来完成的。比如编译Java有Java插件,编译Groovy有Groovy插件,编译Android APP有Android APP插件,编译Android Library有Android Library插件。Gradle中每一个待编译的工程都是一个Project,一个具体的编译过程是由一个一个的Task来定义和执行的。一个Project到底包含多少个Task,其实是由编译脚本指定的插件决定。插件是什么呢?插件就是用来定义Task,并具体执行这些Task的东西
在这里插入图片描述
在这里插入图片描述
参与项目构建的第三方代码叫 --> 插件
参与代码逻辑的第三方代码叫 --> 依赖

Gradle生命周期与回调

Gradle构建生命周期

在这里插入图片描述

生命周期监听(HOOK)

在这里插入图片描述

Gradle JVM 进程

Gradle 构建工具在不同场景下会分别使用3个 JVM 进程:

  • client
  • Daemon
  • wrapper

1.client 进程

client 进程是个轻量级进程,每次构建开始都会创建这个进程,构建结束会销毁这个进程。client 进程的任务是查找并和 Daemon 进程通信:

  • Daemon 进程没启动,client 进程会启动一个新的 Daemon 进程
  • Daemon 进程已经存在了,client 进程就给 Daemon 进程传递本次构建相关的参数和任务,然后接收 Daemon 进程发送过来的日志

像 gradle.properties 里面设置的参数,全局 init.gradle 初始化脚本的任务这些都需要 client 进程传递给 Daemon 进程

2.Daemon 进程

  • Daemon 进程负责具体的构建任务。我们使用 AS 打包 APK 这依靠的不是 AS 这个 IDEA 开发工具,而是 Gradle 构建工具自己启动的、专门的一个负责构建任务的进程:Daemon。每一个版本的 Gradle 都会对应创建一个 Daemon 进程
  • Daemon 进程不依赖 AS 而是独立存在,是一个守护进程,构建结束 Daemon 进程也不会销毁,而是会休眠,等待下一次构建,这样做是为了节省系统资源,加快构建速度,Daemon 进程会缓存插件、依赖等资源
  • 必须注意: 每一个 Gradle 版本都会对应一个 Daemon 进程,机器内若是运行过多个版本的 Gradle,那么机器内就会存在多个 Daemon 进程,AS 开发 android 项目,我推荐使用 Gradle 本地文件,不依靠每个 android 项目中 wrapper 管理 gradle 版本

gradle --status 命令可以查看已启动的 daemon 进程情况:

~ jps
39554 KotlinCompileDaemon
39509 GradleDaemon
39608
39675 Jps~ gradle --status
   PID STATUS   INFO
 39509 IDLE     6.6.1

// INFO 是 gradle 版本号
// Kotlin 语言编写的 Gradle 脚本需要一个新的 daemon 进程出来

wrapper 进程
在这里插入图片描述
wrapper 进程啥也不干,不参与项目构建,唯一任务就是负责下载管理 Gradle 版本。我们导入 Gradle 项目进来,client 进程发现所需版本的 Gradle 本机没有,那么就会启动 wrapper 进程,根据 gradle.properties 里面的参数去自行 gradle-wrapper.jar 里面的下载程序去下载 Gradle 文件

什么是 Task

Gradle中,每一个待编译的工程都叫一个Project。每一个Project在构建的时候都包含一系列的Task。比如一个Android APK的编译可能包含:Java源码编译Task、资源编译Task、JNI编译Task、lint检查Task、打包生成APK的Task、签名Task等。一个Project到底包含多少个Task,其实是由编译脚本指定的插件决定。插件是什么呢?插件就是用来定义Task,并具体执行这些Task的东西

导入插件
插入插件,我们先要导入仓库,也就声明从哪些仓库查找插件和远程依赖,然后再导入插件。只要我们在根项目的 build.gradle 构建脚本中声明导入的插件,那么所有子项目就都可以使用该插件了

根项目 build.gradle 导入插件

buildscript {
    repositories {
        google()   
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.5.0'
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

子项目使用插件

app build.gradle --> 

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
    ....

    defaultConfig {
        ....
    }
    buildTypes {
        ....
    }
}

dependencies {
    ....
}

其中几个 {…} 闭包解释下:

  • buildscript {…} --> 声明仓库、添加插件专用闭包
  • repositories {…} --> 设置远程仓库
  • dependencies {…} --> 添加插件地址,当然也可以添加在 setting.gradle 脚本中使用的远程依赖
    apply --> 使用插件

apply 就是查找插件中的 apply 方法并调用他就是这么简单,gradle 会帮你实例化这么个类,并调用他的方法

buildscript {
  repositories {
    mavenCentral()
    google()
  }
  dependencies {
    classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.3'
  }
}
apply plugin: 'com.jakewharton.butterknife'

apply plugin ‘com.jakewharton.butterknife’ 其实就是调用 com.jakewharton:butterknife-gradle-plugin:10.2.3包中的com.jakewharton.butterknife类的apply方法。

如下所示 自定义gradle插件

class GreetingPlugin implements Plugin<Project> {
    void apply(Project project) {
        project.task('hello') {
            doLast {
                println 'Hello from the GreetingPlugin'
            }
        }
    }
}

// Apply the plugin
apply plugin: GreetingPlugin

获取构建信息的命令

// 1、按自顶向下的结构列出子项目的名称列表
./gradlew projects
// 2、分类列出项目中所有的任务
./gradlew tasks
// 3、列出项目的依赖列表
./gradlew dependencies

依赖管理

查看Android Gradle 依赖树

查看Android Gradle 依赖树

./gradlew :app:dependencies > dependencies.txt
./gradlew app:dependencies --configuration releaseCompileClasspath > dependencies.txt //显示release模式下编译过程中的依赖树

依赖分类
Gradle 依赖分:直接依赖项目依赖本地 jaraar 依赖传递依赖,这几个总规要分清楚的,多少还是有些差别的

  • 直接依赖 --> 在项目中直接导入的依赖,就是直接依赖
implementation 'androidx.core:core-ktx:1.3.2'
  • 项目依赖 --> 这个好理解,app module 依赖 libs module,libs 就是项目依赖
    传递依赖 --> 依赖里面的依赖,好比 rxandroid 里面还依赖了 rxjava,rxjava 对于外层来说就是传递依赖。传递依赖就是 Gradle 做的烂的一个地方,哪个项目中传递依赖不是一层套一层的,最后套了太多层,Gradle 自己分析起来都很耗时,还容易出现问题造成编译失败,有人管这叫: 依赖地狱
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
	 --> 内部依赖了 
	  implementation "io.reactivex.rxjava2:rxjava:x.x.x"

添加依赖

jar: 只有class文件及manifest,不包含资源文件;
arr:包含jar包跟资源文件,生成需要mave插件的支持;
model:完整的AS项目;

jar
添加依赖的方式一般就是这2种了,基本上大家都是直接放到 libs 里的,一个个写太费事

implementation files('hibernate.jar', 'libs/spring.jar')
implementation fileTree(dir: 'libs', include: ['*.jar'])

对于 Gradle Android Plugin 来说,会把 jar 看成一种本地代码资源,implementation fileTree() 是声明本地 java 资源路径。

so 文件
.so 文件和 .java 一样,会被 Gradle 看成一种本地代码资源,只要设置 .so 资源的路径即可
一般有2种方式:

一个是按照 android 插件默认的文件路径放置 .so 文件,这样 android 插件会按照默认的路径查找,引入 so 文件
一个是我们手动设置 .so 资源路径

// 设置 .so 资源路径
android{
   sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }
}

在这里插入图片描述

需要注意的是,so 文件需要放到具体的 ABI 目录下,不能直接放 libs 目录下,一般都是这样的
在这里插入图片描述
x86/x86_64/armeabi-v7a/arm64-v8a 这些叫 ABI,每一种都对应一种 CPU 指令集 ,在 defaultConfig{…} 中设置使用哪些 ABI

android{
    defaultConfig {
        ndk {
            abiFilters "armeabi", "armeabi-v7a", "x86", "mips"
        }
    }
}

远程依赖
Gradle 没有自己的远程仓库,用的是 Maven,Jcenter,Jvy 这些库,所以添加远程依赖,要先声明使用哪个远程仓库
每个 Gradle 脚本都要声明使用的远程仓库,所以根目录脚本才会用 allprojects{…} 给每个子项目都声明远程仓库地址

buildscript {
    ext.kotlin_version = "1.4.10"
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.0.1"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

aar 文件
Gradle 把 aar 文件一样视为远程依赖,所以同样要在 repositories{…} 里声明 aar 文件仓库地址,不过这个仓库的设置就有些麻烦、复杂了

若是 app module 依赖本地 aar,这么写就行了

android{
	...
}

// 声明本地 aar 文件地址
repositories {
	flatDir {
		dirs 'libs'
	}
}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"]) 
    // 添加本地 aar 文件依赖
    implementation(name: 'easeui', ext: 'aar')

但要是 lib 这样的,给别的 module 提供依赖的 module,依赖 aar 文件的话,必须在整个依赖链条上所有的 module 都写上这个 aar 文件所在的仓库地址,一般这种情况,我们都是在根目录脚本 allprojects{…} 里添加 aar 仓库,注意这里 aar 仓库的地址淂写 aar 文件所在 module 这一层级的地址

allprojects {
    repositories {
        google()
        jcenter()
        flatDir {
            dirs '../animal/libs'
        }
    }
}

implementation(name: 'easeui', ext: 'aar')

图示如下:app 依赖 lib module --> lib module 依赖 animal module --> animal module 中有 aar 依赖 easeui.arr

在这里插入图片描述
或者呢你要是嫌麻烦,可以在项目根目录下建一个 libs 文件夹,所有的 aar 都放到里面,然后在跟脚本统一设置下
在这里插入图片描述

结合 implementation、api 理解 compileClasspath、runtimeClasspath

  • compileClasspath --> 中包含的代码、类库,是我们在编写代码时能使用到的类库。这个 path 里要是没有我们想要调的类库,即便我们把远程依赖代码下下来也没用

  • runtimeClasspath --> 中包含的代码、类库,是 app 跑起来之后能找到的类库。即便我们把远程依赖代码下下来并写到 compileClasspath 里了,我们写代码时可以调用对应的类库,但只要没写到 runtimeClasspath 里面去,app 跑起来一样还是会找不到类库,会 crash 的

  • api会传递依赖

举例:A依赖B、B依赖C,A、B、C 都是项目 module

1.若 A implementation B,B implementation C,

  • 那么 在 B 中 C 的类库可以随便用

  • 在 A 中就不能使用 C 的类库,IED 提示找不到对应的类

  • 这是因为 implementation 引入的依赖,会把 C 加入 B 的 compileClasspath 和 runtimeClasspath,会把 C 加入 A 的 runtimeClasspath

  • 因为没有加入 A 的 compileClasspath,所以在 A 项目中使用不了对应的代码,但是因为加入了 A 的 runtimeClasspath,则会把 C 的类库打包进 APK 中

2.若 A implementation B,B api C,那么

  • 在 B 中 C 的类库可以随便用
  • 在 A 中 C 的类库一样可以随便用
  • 这是因为 api 引入的依赖,会把 C 加入 B 的 compileClasspath 和 runtimeClasspath,同样会把 C 加入 A 的 compileClasspath 和 runtimeClasspath
  • 因为 C 即加入了 A 的 compileClasspath ,也加入了 A 的 runtimeClasspath,所以在 A 项目中既能使用 C 的类库,也会把 C 的类库打包进 APK 中

若 B compileOnly C,则 A 无法调用 C 的代码,且 C 的代码不会被打包到 APK 中

若 B runtimeOnly C,则 A、B 都无法调用 C 的代码,但 C 的代码会被打包到 APK 中

依赖决议

依赖决议是指 “在编译过程中, 如果存在某个依赖的多个版本, 构建系统应该选择哪个进行构建的问题”

在这里插入图片描述
A、B、C 都是本地子项目 module,D 是远程依赖

  • 编译时: B 用 1.0 版本的 D,C 用 1.1 版本的 D,B 和 C 之间没有冲突
  • 打包时: 只能有一个版本的代码最终打包进 APK,对于 Gradle 来说这里就有冲突了

不过 Gradle 自有其处理方法,不考虑其他强制设置版本号的手段,就说默认。默认下,Gradle 会使用最新版本的远程依赖。

强制依赖版本

isFoce

isFoce 标记会强制使用该标记版本的依赖

dependencies {
    implementation("io.reactivex.rxjava2:rxjava:2.2.6") {
        isForce = true
    }
    implementation("io.reactivex.rxjava2:rxjava:2.2.10")
}

// 依赖决议使用 2.2.6 版本

注意:

  • 同一个 module 中,对同一个依赖多次书写 isForce,只有第一个会生效,后面的都没用
  • isForce 只作用于当前模块, 不同模块中的 isForce 相互独立
  • isForce 跨模块,这些模块相互依赖,那么以 app 的 isForce 为准,因为 app 的 脚本先执行
  • isForce 的版本并不会反映到 POM 文件中, 这个必须清楚,要使用 isForce 一定要谨慎

isForce 出现的非常早,实际使用起来问题很多,因书写不当很容易造成构建失败,现在建议不要再使用了
isForce 最大的问题是这个:

force 的版本不能比 app 主模块的版本低,要不就报错。比如 app 模块依赖于 lib, 如果 app 中引入了 rxjava:2.2.10, lib 却 force 了 rxjava:2.2.6 则会发生编译错误

遇到这个问题:

  • 去掉 lib 中的 force
  • 可以在 app 中再次 force 该依赖即可,无论高低版本

strictly

strictly 是一种强力依赖版本约束,官方现在推荐使用这个,可以用 !! 简写,这样就会强制使用 2.2.0 版本的依赖了

dependencies {
        implementation("io.reactivex.rxjava2:rxjava") {
        version {
            strictly("2.2.0")
        }
    }
	 // 等价于
	implementation("io.reactivex.rxjava2:rxjava:2.2.0!!") 

}

constraints

constraints 是 strictly 新版本的替代,东西和 strictly 是一样的

dependencies {
    implementation("io.reactivex.rxjava2:rxjava:2.2.6!!")
    constraints {
        implementation("io.reactivex.rxjava2:rxjava:2.2.6!!")
    }
}

但是同样也有问题,constraints 的版本不能比其他的低,要不也会报错

jar 包冲突

上面说过 .jar 文件会以代码的方式添加到最终构建产物中,aar 会直接包含 .jar 中的代码。要是本地项目和远程依赖都引入了同一个 .jar 的话会冲突的,会提示有相同包名+类名冲突的资源,这里的话可以在方便的位置用 compileOnly 代替 implementation

远程依赖冲突

Gradle 在 implementation{…} 中提供了 exclude 设置,可以忽略指定的依赖,被忽略的依赖将被视为从来没有依赖过
先熟悉下 group、module、version 指的都是哪部分

implementation("io.reactivex.rxjava2:rxandroid:2.1.1")

group = io.reactivex.rxjava2
module = rxandroid
version = 2.1.1

一般我们可以这么写

 implementation('org.hibernate:hibernate:3.1') {
        exclude module: 'cglib' 
        exclude group: 'org.jmock' 
        exclude group: 'org.unwanted', module: 'iAmBuggy' 
    }

远程依赖冲突一般我们通过 exclude、force、transitive 解决冲突,其中 force 已经不推荐使用了,下面提供一些范例:

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        def requested = details.requested
        if (requested.group == 'com.android.support') {
            if (!requested.name.startsWith("multidex")) {
                details.useVersion '26.1.0'
            }
        }
    }
}

依赖传递

前文我用 implementation、api 来讲解 compileClasspath、runtimeClasspath,A依赖B、B依赖C,C作为依赖会传递给A。Gradle 就是这么一层层、逐级的合并 path,才能最终知道哪些代码应该打进 APK 文件中,即便这会带来依赖冲突、性能损耗的问题,但是正是这种机制,才能使得代码齐全,不会缺少
我们 implementation 一个远程依赖,依赖传递默认是启动的。当然依赖传递也有操作余地,系统提供了 transitive 让我们自己选择是不是要把依赖传递下去
导入远程依赖,transitive 默认是 true 的,就像下面一样

implementation("io.reactivex.rxjava2:rxandroid:2.1.1"){
	transitive(true)
}

现在我们把 transitive 写成 false 看看
例:app implementation libs、libs api rxandroid,这样我们在 app 中也能够使用 rxandroid 的 API,我们给 libs api rxandroid 设置 transitive(false) 后,app 中就找不到 rxandroid 的类库了,因为依赖无法被传递了

api("io.reactivex.rxjava2:rxandroid:2.1.1"){
	transitive(false)
}

Gradle 中的动态参数

manifestPlaceholders

Gradle 中声明的 manifestPlaceholders 参数,在 AndroidManifest.xml 中可以通过 $hostName 的方式引用到
manifestPlaceholders 可以写在 Gradle 脚本 android{…} DSL 中,常见的应用位置:

defaultConfig {...}、productFlavors{...}、buildTypes{...}
android {
    defaultConfig {
        manifestPlaceholders(["hostName":"www.example.com"])
    }
}

可以在配置文件中的任何位置使用

<?xml .....>
<manifest ....>
    <application ....>
        <activity ....>
            <intent-filter>
                <data android:scheme="http" android:host="${hostName}"/>
            </intent-filter>
        </...>
    </...>
</...>

buildConfigField

buildConfigField 方法会在生成 BuildConfig.java 时, 向其中插入该属性。日志模块我们就是依托这个参数,来统一控制 release 版本不打印日志

android {
    defaultConfig {
        buildConfigField("int", "i", "1234")
        buildConfigField("String", "str", "\"some text\"")
        buildConfigField("boolean", "isRelease", "true")
    }
}

可以看到 build 后,BuildConfig 中有这个参数了
在这里插入图片描述

resValue

resValue 比大家可能见的少,用来向 res/values/strings.xml 中添加数据

android {
    defaultConfig {
        resValue("string", "app_name_test", "some text")
    }
}

在这里插入图片描述

resConfigs

defaultConfig {
	// 资源打包过滤
	resConfigs("en", "ldltr")
}

resConfigs(…) 是系统资源过滤,同一类型的资源,只有 resConfigs{…} 声明的配置才能打入 APK 中,可以用在:defaultConfig {…}、productFlavors{…}、buildTypes{…} 中

  • en: 只选择英文
  • ldltr: 方向性资源上只要从左到右的资源文件

移除某个第三方的依赖

debugImplementation ('me.ele:uetool:1.0.15'){
  exclude group: 'com.android.support', module: 'support-v7'
}

debugImplementation ('me.ele:uetool:1.0.15'){
  exclude group: 'com.android.support'
}

更加方便的方式
有时候,乱七八糟的依赖过多,可以使用如下方案:

在 app的module中:

android{
	configurations.all {
        resolutionStrategy.eachDependency { DependencyResolveDetails details ->
            def requested = details.requested
            if (requested.group == 'com.android.support') {
                if (requested.name.startsWith("appcompat-v7")) {
                    details.useVersion '25.3.0'
                }
                if (requested.name.startsWith("appcompat-v4")) {
                    details.useVersion '25.3.0'
                }

                if (requested.name.startsWith("recyclerview-v7")) {
                    details.useVersion '25.3.0'
                }
            }
        }
    }

}

这样可以强制使用某个版本,不用再一个个去过滤了。

ext 扩展属性

ext{…} 这个 DSL 代码段也是 Project 对象提供的方法。ext{…} 大家都不陌生吧,都是用来做全局参数、依赖的配置。ext{…} 是 Gradle 提供的、让我们定义所需全局变量的代码块,简称:扩展属性

1. 定义 ext

一般我们在根项目脚本中写 ext{…}

// project build.gradle

ext {
    tag = "BB"
    age = 2
}

2. 使用 ext

大家注意这2种使用方式自动提示的环节,很多人抱怨没有代码提示好难用

// app build.gradle

// 方式1:直接使用,sync 之后出现自动提示
println( "name = $tag" )
println( "age = $age" )

// 方式1:借助 rootProject 对象,rebuild 之后出现自动提示
println( "name = ${rootProject.ext.tag}" )
println( "age = ${rootProject.ext.age}" )

3. 进阶使用 ext

1 – 抽象公共配置脚本
这个好理解,ext{…} 写在根目录脚本里有的人说应该拆分、专人专事,于是我们专门写一个 ext{…} 的脚本出来,该脚本一般都叫:config.gradle,然后 apple from 导入本目录脚本就能用了
ext{…} 编译过后是 Project 对象中的一个成员属性,ext{…} 中一般我们都是写 Map 来配置一些属性

// config.gradle

ext {

	// 不同的 DSL 配置块,推荐专门写一个 map 出来,这样方便查找
    android = [
            compileSdkVersion: 28,
            buildToolsVersion: "29.0.1",
            applicationId    : "com.example.androidstudydemo",
            minSdkVersion    : 21,
            targetSdkVersion : 29,
            versionCode      : 1,
            versionName      : "1.0"
    ]
}
// root build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply from: 'config.gradle'
buildscript {

    repositories {
        google()
        jcenter()

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.4.2'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}


// app build.gradle

android {
    compileSdkVersion rootProject.ext.android.compileSdkVersion

   defaultConfig {
        applicationId rootProject.ext.android.applicationId
        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
    }
}    

4. 进阶使用 2 – 抽象子项目脚本基类

这个也不难理解,我们的项目要是有多个 子项目 ,每个子项目中 重复的脚本配置 写起来也是让人讨厌的事,尤其是休休改改的情况下很讨厌的,我们应该延续 java 相面对象中的思路:一处修改,处处使用
这里我们需创建脚本基类,该脚本一般都叫:base_build.gradle,也是通过 apple from 导入子项目脚本就可以了

// base_build.gradle
apply plugin: 'com.android.application'
android {
    compileSdkVersion rootProject.ext.android.compileSdkVersion

    defaultConfig {
        applicationId rootProject.ext.android.applicationId
        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:support-v4:28.0.0'
    implementation 'com.android.support:appcompat-v7:28.0.0'
}

// app build.gradle

apply from: rootProject.file("base_build.gradle")


dependencies {
    implementation 'com.android.volley:volley:1.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
    implementation 'com.google.code.gson:gson:2.8.5'
    implementation 'com.alibaba:fastjson:1.2.60'
    implementation 'org.greenrobot:eventbus:3.1.1'
    implementation 'com.squareup.okhttp3:okhttp:3.8.0'
    implementation 'com.squareup.retrofit2:retrofit:parent-2.6.1'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
    implementation 'io.reactivex:rxjava:1.2.1'
    implementation 'io.reactivex:rxandroid:1.0.1'
    implementation 'com.jakewharton.rxbinding:rxbinding:0.4.0'
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.2'
    releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:2.2'
    implementation 'cat.ereza:customactivityoncrash:2.2.0'
    implementation 'com.github.bumptech.glide:glide:3.7.0'
}

Android Studio项目版本号的统一管理

Android Studio项目版本号的统一管理

Android studio中的BuildConfig类

Android studio中的BuildConfig类

开发中常用的包有jar包 arr包,还有model,区别如下:
jar: 只有class文件及manifest,不包含资源文件;
arr:包含jar包跟资源文件,生成需要mave插件的支持;
model:完整的AS项目;

在build.gradle文件中google()和maven {url’ https://maven.google.com‘}之间是否有任何区别?如果有,那是什么?

allprojects {
    repositories {
        jcenter()
        maven { url 'https://maven.google.com' }
        // OR
        google()
    }
}

google()存储库是Google maven存储库的快捷方式.它是在Gradle 4.x中引入的.使用的实际存储库URL是https://dl.google.com/dl/android/maven2/,和 https://maven.google.com实际指向同一存储库.

Android多渠道productFlavors同时开发两个类似的app

Android多渠道productFlavors同时开发两个类似的app
Android 中实现差异化打包权威指南

Android Maven 打包不同的Flavors 的aar文件

Android Maven 打包不同的Flavors 的aar文件
maven gradle插件如何上传多渠道library

pom文件

productFlavors {
    all {
       ...
    }
    sdk {
       ...
    }
}
apply plugin: 'maven'

import org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact

//导入类
configurations {
    sdkArchives
    AllArchives
}

artifacts {
    AllArchives new DefaultPublishArtifact("all", "aar", "aar", null, new Date(),
            new File("build/outputs/aar", "Zinyan-all-release.aar"))
    sdkArchives new DefaultPublishArtifact("sdk", "aar", "aar", null, new Date(),
            new File("build/outputs/aar", "Zinyan-sdk-release.aar")) //这个aar文件的名称> 你需要根据你的本地文件进行修改
}

//全部SDK
task uploadAll(type: Upload, group: "upload", dependsOn: 'assembleAll') {  // assembleAll 就会帮我们生成相关的aar文件的task。  Gradle/XXX/Tasks/build/assembleXXXX  你自己的项目进行选择。 
    setConfiguration(project.configurations.getByName("AllArchives"))

    repositories.mavenDeployer {
        def mavenDirPath = file('D:\\Zinyan\\mavenLib') 
        repository(url: "file://${mavenDirPath.absolutePath}")

        pom.project {
            groupId "com.zinyan.dev" // 包名
            artifactId "all" // module的名字
            version '1.0.0'// 版本号
        }
        // 特殊的dependencies手动添加 例: internalImplementation 'com.tencent.tbs:tbssdk:44165'
 		dependencies{
             dependency {
                 groupId "com.tencent.tbs"
                 artifactId "tbssdk"
                 version "44165"
             }
        }
        //如果不加下面的pom文件就不正确
        pom.withXml {
            def dependenciesNode = asNode().appendNode("dependencies")
            configurations.implementation.allDependencies.forEach() {
                Dependency dependency ->
                    if (dependency.version != "unspecified" && dependency.name != "unspecified") {
                        def dependencyNode = dependenciesNode.appendNode('dependency')
                        dependencyNode.appendNode('groupId', dependency.group)
                        dependencyNode.appendNode('artifactId', dependency.name)
                        dependencyNode.appendNode('version', dependency.version)
                    }
            }
        }
    }
}
//第二个SDK
task uploadSdk(type: Upload, group: "upload", dependsOn: 'assembleSdk') {
    setConfiguration(project.configurations.getByName("sdkArchives"))

    repositories.mavenDeployer {
         def mavenDirPath = file('D:\\Zinyan\\mavenLib') 
        repository(url: "file://${mavenDirPath.absolutePath}")

         pom.project {
            groupId "com.zinyan.dev" // 包名
            artifactId "sdk" // module的名字
            version '1.0.0'// 版本号
        }
        pom.withXml {
            def dependenciesNode = asNode().appendNode("dependencies")
            configurations.implementation.allDependencies.forEach() {
                Dependency dependency ->
                    if (dependency.version != "unspecified" && dependency.name != "unspecified") {
                        def dependencyNode = dependenciesNode.appendNode('dependency')
                        dependencyNode.appendNode('groupId', dependency.group)
                        dependencyNode.appendNode('artifactId', dependency.name)
                        dependencyNode.appendNode('version', dependency.version)
                    }
            }
        }
    }
}

Gradle插件开发系列之gradle插件调试方法

Gradle插件开发系列之gradle插件调试方法

直接在gradle窗口选择任务直接右键debug

组件化架构下实现arr与源码的切换

组件化下如何优雅进行本地调试,即aar依赖与module依赖动态切换
aar和源码切换插件Plus

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值