1、Gradle是什么,有什么作用
Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具。
它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。面向Java应用为主。
当前其支持的语言限于Java、Groovy、Kotlin和Scala,计划未来将支持更多的语言。基于 groovy 脚本构建,其 build 脚本使用 groovy 语言编写。
android studio 中 Gradle 可以帮我们编译 构建 打包项目 可以配置自己的task任务,可以很方便的去引用第三方的类库
2、Gradle在Android studio的具体用法
太杂了,我直接贴代码吧,加有注释 build.gradle
/**
* Gradle 是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化建构工具。
* 它使用一种基于 Groovy 的特定领域语言(DSL)来声明项目设置,抛弃了基于 XML 的各种繁琐配置。
*
* 简单来说,Gradle 是一种项目构建工具, 它可以帮你管理项目中的
* 差异、依赖、编译、打包、部署 ......,你可以定义满足自己需要的构建逻辑,
* 写入到 build.gradle 中供日后复用。
*
* Gradle 是一个构建工具,但它需要特定的插件来工作。Android Plugin for Gradle 即是 Gradle 的 Android 插件。
* Android Studio 构建系统基于 Gradle,Gradle 的 Android 插件 添加了特定于构建 Android 应用程序的几项功能。
* 虽然 Android 插件通常以 Android Studio 的锁定步骤更新,
* 但插件(以及其余的 Gradle 系统)可以独立于 Android Studio 运行,并单独更新。
*
* Gradle是一个独立运行的程序,不但可以与AndroidStudio协同工作还可以和Eclipse等IDE配合使用。
* 但由于Gradle发展速度比较快,导致Gradle版本不一,
* 故每个 Android 插件版本(Android Plugin for Gradle)需要与特定的 Gradle 版本相匹配才能编译成功。
* 为了获得最佳性能,应该使用最新版本的 Gradle 和 Android 插件。
*/
plugins {
id 'com.android.application'//应用com.android.application 插件构建此模块
}
//开始配置安卓特定的编译选项
android {
namespace 'com.example.gradledemo'
compileSdk 33 //编译的SDK版本,最佳选择为最新的API级别
// buildToolsVersion //编译的Tools版本,最佳选择为最新的API级别
//封装默认设置和编译变量,能根据编译系统动态得重写AndroidManifest.xml中的属性
defaultConfig {
applicationId "com.example.gradledemo" //应用程序的包名
minSdk 24 //支持的最低版本,操作系统会拒绝将应用安装在系统版本低于此标准的设备上
targetSdk 33 //支持的目标版本,最佳选择为最新的API级别
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" //允许自动化测试
versionCode 1 // 版本号
versionName "1.0" // 版本名
multiDexEnabled true //开启分包
ndk { // 设置支持的SO库架构 这些叫 ABI,每一种都对应一种 CPU 指令集
/**
* Android 平台 CPU 有三大类:ARM、x86、MIPS,其中 x86、MIPS 已经被彻底淘汰了,大家集成 .so 只要考虑 ARM 平台架构就行了
* ARM 平台架构主要有3种,下面说的代对应的是架构:
* armeabi: 第5代、第6代 ARM 处理器,早期 android 手机用,A5/7/8/9 核心用的都是这个架构
* armeabiv-v7a: 第7代、32位 ARM 处理器架构,带浮点数计算能力。A15/17 核心用的都是这个架构,一般现在也少见了,也都淘汰了
* arm64-v8a: 第8代、64位 ARM 处理器架构,A32/35/53/57/72/73 核心用的都是这个架构,一般现在的 ARM 处理器都在这个范围内
*/
abiFilters 'armeabi', 'armeabi-v7a', 'arm64- v8a', 'x86', 'x86_64'
}
multiDexEnabled true //是否支持分包
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"//junit单元测试
resConfigs 'en'//中文资源
resConfigs "xhdpi" //只使用xhdpi 下的资源文件
multiDexEnabled true //分包,指定某个类在main dex
multiDexKeepProguard file('multiDexKeep.pro') // 打包到main dex的这些类的混淆规制,没特殊需求就给个空文件
multiDexKeepFile file('maindexlist.txt') // 指定哪些类要放到main dex
}
//开启databind支持
dataBinding {
enabled = true
}
//签名信息
signingConfigs {
production {
//签名文件路径
storeFile rootProject.ext.signing.storeFile
//密码
storePassword rootProject.ext.signing.storePassword
//别名
keyAlias rootProject.ext.signing.keyAlias
//别名密码
keyPassword rootProject.ext.signing.keyPassword
}
}
//构建类型,生成包的配置
buildTypes {
// 开发环境
debug {
debuggable true // 是否支持断点调试 默认false
jniDebuggable true // 是否可以调试NDK代码 默认false
renderscriptDebuggable true // 是否开启渲染脚本RenderScript调试功能,默认为false
zipAlignEnabled true // 是否对APK包执行ZIP对齐优化,减小zip体积,增加运行效率 默认true
minifyEnabled true // 是否对代码进行混淆,默认false
shrinkResources true// 移除无用的资源文件 是否自动优化未使用的资源,该配置生效的前提是minifyEnabled必须为true,默认false
// proguardFiles 指定混淆的规则文件
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
versionNameSuffix "-debug"//可以版本名称后面追加相关信息
applicationIdSuffix ".debug"//包名添加后缀 可以控制不同构建类型不同的包名
//自定义资源信息相当于value 下的String.xml里的内容 debug环境下 定义响应的项目名称
resValue "string", "app_name", rootProject.ext.android.debugAppName
//manifest 参数配置项目图标 debug环境下的桌面图标显示 在 manifest 清单文件中引用
manifestPlaceholders = [app_icon: rootProject.ext.android.debugAppIcon]
//自定义参数 在 Buildconfig使用 这里不同的环境定义不同的url
buildConfigField("String", "API_URL", rootProject.ext.apiUrl.debugUrl)
//配置签名信息
signingConfig signingConfigs.production
externalNativeBuild {
ndkBuild {
arguments 'NDK_DEBUG=1'
}
}
}
//预上线
preRelease {
resValue "string", "app_name", rootProject.ext.android.preReleaseAppName
manifestPlaceholders = [app_icon: rootProject.ext.android.preReleaseAppIcon]
zipAlignEnabled true
shrinkResources true
versionNameSuffix "-preRelease"
applicationIdSuffix ".preRelease"
signingConfig signingConfigs.production
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
buildConfigField("String", "API_URL", rootProject.ext.apiUrl.preRelease)
}
release {// 线上正式
resValue "string", "app_name", rootProject.ext.android.releaseAppName
manifestPlaceholders = [app_icon: rootProject.ext.android.releaseAppIcon]
zipAlignEnabled true
shrinkResources true
signingConfig signingConfigs.production
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
buildConfigField("String", "API_URL", rootProject.ext.apiUrl.release)
}
}
/**
* productFlavors 字面翻译是产品口味,在多渠道打包用的比较多,或者是针对同一款应用不同的使用限制。
* 在productFlavors 中可以重写 defaultConfig 中的配置。在默认情况下编译系统是没有创建 productFlavors 的。
* 这里示范创建了付费和免费两种产品特性,每种特性定义了不同的应用id,所以同一款手机可以同时安装者款应用
*/
productFlavors {
free {
applicationId 'com.example.myapp.free'
}
paid {
applicationId 'com.example.myapp.paid'
}
}
/**
* 拆分专用版本的apk,以减小应用的提交
* 比如:jni时分别拆分成arm版和x86版或者根据屏幕密度拆分
*/
splits {
// 屏幕密度分割设置
density {
// 启用或禁用密度分割机制
enable false
// 从分割中排除这些密度
exclude "ldpi", "tvdpi", "xxxhdpi", "400dpi", "560dpi"
}
}
// 打包完成后的一些copy操作和修改apk名字或路径等操作
android.applicationVariants.all { variant ->
// delete previous files first
delete "${buildDir}/intermediates/merged_assets/${variant.dirName}"
variant.mergeAssets.doLast {
def sourceDir = "${buildDir}/../../../../.."
copy {
from "${sourceDir}"
include "assets/**"
include "src/**"
include "jsb-adapter/**"
into outputDir
}
copy {
from "${sourceDir}/main.js"
from "${sourceDir}/project.json"
into outputDir
}
}
//修改apk包名
variant.outputs.all { output ->
outputFileName = "app-${variant.name}-${defaultConfig.versionName}-${defaultConfig.versionCode}.apk"
}
//混淆对应文件输出
variant.outputs.each { output ->
if (variant.getBuildType().isMinifyEnabled()) {
variant.assemble.doLast{
copy {
from variant.mappingFile
into "${projectDir}/mappings"
rename { String fileName ->
"mapping-${variant.name}.txt"
}
}
}
}
}
}
// 声明本地 aar 文件地址
repositories {
flatDir {
dirs 'libs'
}
}
//jdk 配置
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
//lib包配置 设置 .so 资源路径
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
// 多渠道/多环境 的不同配置
flavorDimensions("default")
productFlavors {
qudao1 {
dimension "default"
//自定义项目名称
resValue "string", "app_name", "渠道1"
//自定义参数 在BUildConfig 里调用
buildConfigField("String", "orgId", '""')
}
qudao2 {
dimension "default"
resValue "string", "app_name", "渠道2"
buildConfigField("String", "orgId", rootProject.ext.channel.csOrgId)
}
}
//执行lint检查,有任何的错误或者警告提示,都会终止构建,我们可以将其关掉。
lintOptions {
abortOnError false
checkReleaseBuilds false
}
//文件重复
packagingOptions {
exclude 'lib/arm64-v8a/ffmpeg.so'
}
configurations {
//编译期排除commons模块
compile.exclude module: 'commons'
//在整个构建过程中排除com.squareup.retrofit2:adapter-rxjava
all*.exclude group: 'com.squareup.retrofit2', module: 'adapter-rxjava'
}
//全局强制使用
configurations.all {
resolutionStrategy {
force 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
}
}
}
/**
* Gradle依赖管理是依靠俩个classpath:compileClasspath、runtimeClasspath
* compileClasspath:编译时能使用的代码和类,当一个组件参与编译时,Gradle会将其放在compileClasspath中
* runtimeClasspath:运行时使用的代码和类,当一个组件参与打包时,Gradle就会将其放在runtimeClasspath中
* 编译时:代码还在编写阶段,只要还没有编译为class,就是编译时
* 运行时:当编译成class文件,在机器上运行的时候叫做运行时
* compileClasspath中含有的代码和类库,是我们在编写代码的时候需要使用到的类库,如果这里面没有的类库,我们编写时是会找不到该类的
* runtimeClasspath这个里面主要包括app运行时需要的类库,如果这个里面没有包含的库,那么运行时找不到类而crash
* implementation、api 这些操作符只是对依赖库不同的操作方式,其核心的逻辑就是,从远程拉下来的库到底是放在compileClasspath中还是runtimeClasspath还是俩个都放
*/
/**
* 配置项目的依赖关系
* 三种依赖方法:1.本地依赖,2.库依赖,3.远程依赖
* 两种依赖方式:
*
* 1.implementation,会添加依赖到编译路径,并且会将依赖打包输出到aar/apk,但编译时不会把依赖暴露给其他moudle
* 比如:A implementation B B implementation C,
* 在B中,可以使用C中类库,
* 在A中,不能使用C只给的类库,但是可以使用B中类库
* 这是因为implementation引入的依赖,会把C加入B的compileClasspath和runtimeClasspath,会把C加入A的runtimeClasspath
* 因为C没有加入A的compileClasspath,所以A没有办法在编译时访问C中的类库,又是因为C加入A的runtimeClasspath,所以A可以在运行时访问C类库
*
* 2.api,会添加依赖到编译路径,并且把依赖打包输出到aar/apk,依赖可以传递
* 比如:A implementation B B api C,
* 在B中,可以使用C中类库
* 在A中,可以使用B中类库,也可以使用C中类库
* 因为api引入的依赖,会把C加入B的compileClasspath和runtimeClasspath,
* 同时会把C加入A的compileClasspath和runtimeClasspath,所以A也可以在编译时访问C中类库
*
* 3.compileOnly,依赖只在编译时使用,不会打包到aar/apk运行时不能使用
* 比如:A implementation B B compileOnly C
* A访问不到C的代码,B可以访问C,且C不会打包到apk中
*
* 4.runtimeOnly,依赖编译时不能使用,只会打包到aar/apk运行时使用
* 比如:A implementation B B compileOnly C
* AB都不可以调用C中代码,但是C会打包到APK中
*
* 5.annotationProcessor,用于注解处理器的依赖配置
* 6.testImplementation,用于指定在测试代码的依赖。
* 7.androidTestImplementation,用于指定在测试代码的依赖。
* 8.debugImplementation,
* 9.releaseImplementation,
* 10.unitTestImplementation,
*
* isForce, 表示强制使用该版本的依赖
* strictly, 一种强力版本约束,可以使用(!!)简写
* exclude, 移除一个依赖,设置忽略指定的依赖,被忽略的依赖就被视为从来没有依赖,目前我测试的情况看来,这个只适用于远程依赖
* transitive, 是否允许依赖传递
* jar冲突, 如果app引用一个aar,arr中有一个xx.jar,而app中又再次引用这个xx.jar,
* 这个时候就需要让aar中引用jar的操作符用 compileOnly 代替 implementation
*
* 版本号法则:
* 1.3, 1.3.0-beta3 --> 固定版本号
* [1.0.0, 1.3.0) --> >= 1.0.0 < 1.3.0 ,[ 含 = ,) 不含 =
* 1.+, [1.0,) --> >= 1.0 版
* latest.integration、latest.release --> 最新版本
*/
dependencies {
// 库依赖
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
//测试需要的依赖包,大部分仅支持debug模式下,relase可调用不到哦!
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//动态版本号
implementation 'com.android.support.constraint:constraint-layout:+'
// 本地依赖,'../libs'下所有的.jar和.aar文件都添加到项目构建中
implementation fileTree(dir: '../libs', include: ['*.jar', '*.aar'])
// 本地依赖,将指定文件添加到依赖中
implementation file('libs/aaa.jar')
// 本地依赖,依次将多个指定文件添加到依赖中
implementation files('libs/aaa.jar', 'libs/bbb.jar')
// 本地依赖,添加AndroidLibrary类型的Module到依赖中
implementation project(':libcocos2dx')
// 远程依赖的日常写法 第三方开源库
implementation 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0'
// 远端依赖的完整写法
implementation group: 'com.tencent.mm.opensdk', name: 'wechat-sdk-android-without-mta', version: '6.8.0'
api 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0'
compileOnly 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0'
runtimeOnly 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0'
annotationProcessor 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0'
implementation('com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0') {
isForce = true//在版本冲突的情况下优先使用3.1版本
}
implementation('com.tencent.mm.opensdk:wechat-sdk-android-without-mta') {
version {
strictly("6.8.0")
}
}
implementation('com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0') {
//排除特定的依赖
exclude module: 'cglib' //by artifact name
exclude group: 'org.jmock' //by group
exclude group: 'org.unwanted', module: 'iAmBuggy' //by both name and group
}
//group和module代表的意义
implementation("org.hibernate:hibernate:3.1")
group = org.hibernate
module = hibernate
version = 3.1
api('org.hibernate:hibernate:3.1') {
// 禁用依赖传递
// 传递依赖:A => B => C ,B 中使用到了 C 中的依赖,
// 如果打开传递依赖,则 A 能使用到 B中所使用的 C 中的依赖,
// 默认都是打开,即 true
transitive = false
}
//重复引用问题
compile ('com.squareup.retrofit2:adapter-rxjava:2.1.0'){
// 冲突时优先使用该版本
force = true
// 依据构建名称排除
exclude module: 'rxjava'
// 依据组织名称排除
exclude group: 'com.squareup.retrofit'
// 依据组织名称+构件名称排除
exclude group: 'com.squareup.retrofit', module: 'rxjava'
// 为本依赖关闭依赖传递特性
transitive = false
}
}