Android Gradle的神奇之处 ---- AGP

AGP,Android Gradle Plugin,安卓Gradle插件,在根build.gradle中引入的classpath就是Android的gradle插件

classpath "com.android.tools.build:gradle:7.0.3"

android {
    compileSdk 31

    defaultConfig {
        applicationId "com.study.sensortrackapp"
        applicationIdSuffix "apk"
        minSdk 21
        targetSdk 31
        versionCode 1
        versionName "1.0"
		manifestPlaceholders = [APP_NAME:"我的APP"]

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

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

1 defaultConfig

先从android这个节点开始,这些节点都是从com.android.application这个插件中提供的;defaultConfig是默认配置,这些信息是保存在BuildConfig这个类中

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "com.study.sensortrackapp";
  public static final String BUILD_TYPE = "debug";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
}

applicationId:这个应用的唯一表示,默认就是当前app的包名,但不是类的包名
applicationIdSuffix:给applicationId添加一个后缀
minSdk:当前应用的最小版本,不能安装在低于minSdk版本的手机上
targetSdk:目标版本,其实是为了做兼容使用;设置了目标版本31,意味着可以使用31版本的新特性,但是同样也可以兼顾 [ minSdk,targetSdk) 的老用户,所以在一些代码逻辑中会出现,如果超过某个版本,就会使用哪个API
versionCode:版本号,版本升级的时候,会用来判断是否是新版本
versionName:版本名称
manifestPlaceholders:清单文件占位符,map类型的数据结构

//Manifest文件中使用
android:label="${APP_NAME}"
//Merged Manifest中查看
android:label = 我的APP

2 productFlavors

直译是产品风味,其实就是项目构建的变种,例如在多渠道打包的时候,需要打华为应用市场,或者小米应用市场的渠道包,就需要在productFlavors中做相对应的配置

flavorDimensions "channel"

flavorDimensions就是对变种的描述,也可以看做是变种的维度,defaultConfig可以看做是默认的产品风味,channel就是从渠道维度的变种,而且声明了维度就必须要使用,否则会报错

productFlavors{
    huawei{
        dimension "channel"
        manifestPlaceholders = [CHANNEL_NAME: "华为渠道"]
    }

    xiaomi{
        dimension "channel"
        manifestPlaceholders = [CHANNEL_NAME: "小米渠道"]
    }
}

在productFlavors中,就创建变种的类型,像华为渠道、小米渠道分类,dimension就是维度的类型,这里是channel
在这里插入图片描述
这样在构建的变种中,就有4类产品,在切换构建类型的时候,Manifest清单文件也在跟着变化

applicationVariants.all{ variant->
    variant.outputs.all{ output->
        println "$output"
    }
}

通过applicationVariants可以遍历获取这4个变种,获取每个变种的输出文件,就是之前讲到过的packageDebug任务

如果要对每个渠道打包,自定义输出的apk类型,就需要在输出之前 就把apk名称定义好

applicationVariants.all{ variant->
    variant.outputs.all{ output->
        def outputFile = output.outputFile
        if(outputFile != null && outputFile.name.endsWith(".apk")){
            //遍历所有的产品风味
            productFlavors.each{ flavor->
                outputFileName = "v${defaultConfig.versionName}_${flavor.manifestPlaceholders.CHANNEL_NAME}.apk"
            }
        }
    }
}

在打包签名之后,对应的会生成对应的huawei文件夹,其中就包含了我们自定义的apk名称
在这里插入图片描述
在productFlavors中定义的属性,像dimension、manifestPlaceholders,可以直接拿到,如果想要更多的值,都可以放在manifestPlaceholders数组中

productFlavors.dimension
productFlavors.manifestPlaceholders.CHANNEL_NAME

对应的在huwei/BuildConfig中就多了一个属性FLAVOR

public static final String FLAVOR = "huawei";

3 buildTypes

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

    debug{
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

buildTypes可以看做是构建模式,主要就是分为debug模式和release模式,如果想要自定义属性,可以使用buildConfigField,在BuildConfig中添加属性

buildConfigField("String","type","\"3\"")

4 sourceSets

sourceSets用来指定,某个文件夹所在的路径;例如我们在libs文件夹下添加了so文件,或者在jniLibs下添加了so文件,都需要执行这个路径

sourceSets {

    main{
        jniLibs.srcDirs = ['jniLibs']
        java.srcDirs = ['src']
        exclude 'TestActivity'
    }
}

这是在src/main文件下的路径,当然也可以设置清单文件的路径;如果在打包的时候,不想某些文件打进包,可以使用exclude排除

5 Dex分包

当我们的项目在打包apk的时候,如果方法数超过65535就会导致打包apk失败(一个dex方法数 > 65535),这种情况当然也有概率出现,当我们的项目依赖很多三方库或者组件化开发,方法数很有可能超过65535

其中的原因就是,dexOpt(apk检索工具)会把每一个类的方法id检索起来,保存在一个链表中,然后这个链表的长度使用short类型来保存的,这就使得方法数id不能超过65535

在Android 5.0之前(minSdk 21),使用Dalvik虚拟机将应用限制为每个 APK 只能使用一个 classes.dex 字节码文件,这样就非常容易超限,所以为了绕开这个限制,需要给Dex分包,下面就是Dex分包的步骤

步骤1:multiDexEnabled true

defaultConfig {
   ......
   multiDexEnabled true
   testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

步骤2:添加MultiDex依赖

implementation 'androidx.multidex:multidex:2.0.1'

步骤3:MultiDexApplication创建

class MyApplication : MultiDexApplication(){
    
}

在清单文件中声明这个application之后,就绕开了这个63335(64K)限制

在Android 5.0之后,就已经默认开启了分包,不再需要做这些设置
在这里插入图片描述
我们看到这里是分了3个包,classes.dex、classes2.dex、classes3.dex,其中classes.dex中主要是放置了一些依赖项的源码
在这里插入图片描述
classes2.dex主要是存放了一些R文件
在这里插入图片描述
classes3.dex包中就是我们自己写的代码
在这里插入图片描述

6 aar打包 + 上传maven

先创建一个module,比如我最近要埋点了,我自己创建一个module,我要打包一个aar让大家用
在这里插入图片描述
module创建完成之后,通过task/assemble打包成一个aar,添加到app项目的libs目录下

implementation files('libs/SensorHelper-release.aar')

使用这样的方式依赖aar会有问题,需要声明一下路径

Caused by: org.gradle.internal.typeconversion.UnsupportedNotationException: Cannot convert the provided notation to a File or URI: {name=SensorHelper-release.aar, ext=aar}.
The following types/formats are supported:
  - A String or CharSequence path, for example 'src/main/java' or '/usr/include'.
  - A String or CharSequence URI, for example 'file:/usr/include'.
  - A File instance.
  - A Path instance.
  - A Directory instance.
  - A RegularFile instance.
  - A URI or URL instance.

声明路径需要在setting.gradle中的Repository中声明,这样使用aar就是直接从lib仓库里找aar

flatDir {
   dirs 'libs'
}

一般情况下,lib都是存在自己公司的maven仓库里,需要的时候,从maven仓库里拉下来,都是aar依赖,这里需要依赖maven插件

如果想要上传maven仓库,需要使用maven的插件,在gradle 7.0以上的版本需要使用”maven-publish“这个插件,7.0以下的版本使用maven插件

id 'maven-publish'

在gradle7.0以上,使用了publishing来发布maven私服,7.0以下使用的是uploadArchives,那么这里就着重介绍publishing发布。

publishing{

    repositories {
        maven {
            allowInsecureProtocol true //非https仓库
            url MAVEN_URL
            credentials {
                username USERNAME
                password PASSWORD
            }
        }
    }

    publications{

        Publish(MavenPublication){

            groupId = "com.github.sensor"
            def projectName = rootProject.getName()
            artifactId = projectName//该aar包的名称
            version = "1.0.0"//
        }
    }
}

repositories是maven私服的配置,url是maven仓库的地址,用户名和密码主要是用来拉取代码时的鉴权;
publications主要就是用来发布aar,这里感觉讲的比较粗,我需要再细化一点儿再发布出来,这个技术其实也是很重要的,我先要搭建一个自己的maven私服

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Awesome_lay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值