前言
在前几篇文章中,已经讲AGP相关配置讲解完毕。从这一篇开始将会开启AGP实战相关的内容。
本篇实战内容:
- AGP实战一:启用multiDex打包
- AGP实战二:aar打包发布maven
1. AGP实战一:启用multiDex打包
我们编写代码难免会导入三方资源库,几个版本过后阔能就会出现65535方法数限制这个错误。因为DexOpt会把每一个类的方法id检索起来,存在一个链表结构里面。这个链表的长度是用short类型来保存的,这就使得方法数id不能超过65535。
所以说一个dex文件是不能超过65535个方法数量,通过打包多个dex文件来解决问题。
我们先来看看正常情况未使用multiDex打包的APK结构:
如图所示
这里有且仅有一个dex包,当方法数如果超过65535的时候,打包时就会报错。为了避免报65535这个错,下面就开始如何避免该问题。
android {
compileSdkVersion 30
defaultConfig {
applicationId "com.hqk.gradledemo05"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
// DexOpt会把每一个类的方法id检索起来,存在一个链表结构里面。
// 这个链表的长度是用short类型来保存的,这就使得方法数id不能超过65535。
// 一个dex方法数不能超出65535.
// 1.设置multiDexEnabled true
// 2.创建MyApplication 继承MultiDexApplication
// 3.AndroidManifest指定MyApplication
// 4.或者重写attachBaseContext 调用MultiDex.install(this)
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
}
这里将multiDexEnabled
设置成了true,过后就要对Application进行改造
class MyApplication : /*MultiDexApplication()*/Application() {
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
MultiDex.install(this)
}
}
这里如注释所说,有两种方式,要么直接继承MultiDexApplication
;要么继承普通Application
但要重写对应attachBaseContext
方法并且执行MultiDex.install(this)
代码。比如说集成Tinker热修复的时候,MyApplication 就可以用第二种方式。
现在我们重新打包编译看看效果:
如图所示
打包好的APK已经自动帮我们分包了。接下来开启第二个实战:
2. AGP实战二:aar打包发布maven
2.1 什么是aar?
- aar就是Android library的二进制归档文件,包含所有资源,class以及res资源文件全部包含。简单来说就是android library工程进行单独打包后的产物
- 将aar解压(后缀改为.zip,再解压文件)打开后,可以看到每个aar解压后的内容可能不完全一样,但是都会包含AndroidManifest.xml,classes.jar,res,R.txt
2.2 如何打包aar
- 先在项目工程中创建library,并且在主工程中依赖这个librar
- 然后在library的任务集中找到assemble这个任务
- 调用这个assemble任务进行对library打包,会生成对应的aar文件,存放在当前library工程的build/outputs/aar目录下
2.3 依赖aar
- 可以把aar放入到libs文件夹下,然后通过相对路径的方式依赖进来
- implementation files(‘libs/xxxxxx.aar’)
- 或者通过添加respositories{flatDir{dirs ‘libs’}},然后在进行依赖
- implementation files(name:‘xxxxxx.aar’, ext:‘aar’)
- 还可以通过把aar发布到maven仓库,然后通过maven来管理这些远程的aar文件,具体依赖就跟使用第三方git上的这些library一样了
如图所示
这里将打包以及前两种引入aar的方式都在这张图标识了出来,不过这些都不是重点,直接一笔带过。我们的重点是第三个:发布到maven仓库,然后通过maven实现远程依赖。
2.4 通过maven脚本插件发布
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'maven'
}
android {
...略-
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!下面AAR的文件名改成你放到libs文件夹里的文件名
def coreAarFile = file('libs/mylibrary-release.aar')
artifacts {
archives coreAarFile
}
uploadArchives {
repositories.mavenDeployer {
pom.groupId = "com.hqk.library"
pom.artifactId = "mylibrary"
pom.version = "1.0.0"
//pom.version = '1.0.0-SNAPSHOT'
//自定义本地仓库
repository(url: uri('../repostory'))
}
}
开头引入了 maven
脚本插件,随后指定需要发布的aar,并且设置对应的信息,最后指定与本地仓库。
如图所示
执行右侧task,执行完毕后,左侧将会生成本地库相关的文件,此时回到项目的bulid.gradle
文件
allprojects {
repositories {
google()
mavenCentral()
// jcenter() // Warning: this repository is going to shut down soon
maven {
//F:\AndroidProjectDemo\gradledemo05
url 'file://F://AndroidProjectDemo//gradledemo05//repostory'
}
}
}
将本地maven仓库地址引入进来,接着回到项目的bulid.gradle
就可以通过implementation
导入aar了:
android{
...略
dependencies {
...略
implementation 'com.hqk.library:mylibrary:1.0.0'
}
}
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!下面AAR的文件名改成你放到libs文件夹里的文件名
def coreAarFile = file('libs/mylibrary-release.aar')
artifacts {
archives coreAarFile
}
uploadArchives {
repositories.mavenDeployer {
repository(url: uri('../repostory'))
pom.groupId = "com.hqk.library"
pom.artifactId = "mylibrary"
pom.version = "1.0.0"
}
}
编译构建成功时就能使用 mylibrary
里面的代码逻辑了。
完美运行!
但是!!敲黑板了!!这种方式在Gradle6过后就被废弃了。所以我们还得学习第二种方式,通过maven-publish
发布到仓库。
2.5 通过maven-publish脚本插件发布
准备工作:先将原来的依赖方式清除!
项目工程的build.gradle
allprojects {
repositories {
google()
mavenCentral()
// jcenter() // Warning: this repository is going to shut down soon
maven {
//F:\AndroidProjectDemo\gradledemo05
// url 'file://F://AndroidProjectDemo//gradledemo05//repostory'
url 'file://F://AndroidProjectDemo//gradledemo05//repository03'
}
}
}
重新依赖了新的本地仓库,在这里文件夹不存在不要紧,可以不用手动创建。
项目build.gradle
// implementation 'com.hqk.library:mylibrary:1.0.0'
注释掉原有的依赖!
//import com.hqk.mylibrary.TestUtil
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// TestUtil.print()
}
}
只要关于之前依赖相关的全部注释掉。到这里就与上面那种方式没有任何关系了。可以开始写新的脚本了。
进入对应library下的build.gradle ,添加如下脚本:
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'maven-publish'
}
android{
...略
}
...略
dependencies {
...略
}
//上传源码对应的task
task generateSourcesJar(type: Jar) {
from android.sourceSets.main.java.getSrcDirs() // 源码路径
archiveClassifier= "sources"
}
def versionName = "1.1.1"
afterEvaluate{
publishing{
repositories {
maven{
//自定义本地仓库
url="F://AndroidProjectDemo//gradledemo05//repository03"
}
// // 定义一个 maven 仓库
// maven {
// //在这里放远程仓库地址
// url = "https://xxxxxxxx"
// // 仓库用户名密码
// credentials {
// username = "root"
// password = "root"
// }
// }
}
publications{
maven(MavenPublication) {
//这个 components 表示 library构建成功后对应的Android组件
from components.release
artifact generateSourcesJar // 上传源码
groupId = "com.hqk.library"
artifactId = "mylibrary"
version = versionName
}
}
}
}
注意看,这里依赖的是maven-publish插件,随后在afterEvaluate
这个闭包里实现了maven-publish插件里面的publishing
对应的task。发布脚本就这么点,先clear项目删除.gradle
文件夹,然后在构建编译,当编译没报错时,则说明成功了一大半。
如图所示
点击右侧对应的publish,运行成功后,左侧将会生成对应maven的本地仓库文件夹。
此时进入项目里的bulid.gradle
这次重新依赖仓库里面的aar。
// implementation 'com.hqk.library:mylibrary:1.0.0'
implementation 'com.hqk.library:mylibrary:1.1.1' //这次版本为 1.1.1
在对应的业务逻辑代码
import com.hqk.mylibrary.TestUtil
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
TestUtil.print()
TestUtil.hello()
}
}
如图所示
通过鼠标也能进入查看对应aar的逻辑代码,而且还能查看对应的注释。
结束语
好了,到这里,本篇差不多结束了!相信小伙伴们对Gradle有了深一步的理解。