Android中的Gradle文件

402 阅读10分钟

一、项目中的Gradle文件

新建了一个工程,Gradle文件如下

image.png

二、Gradle文件具体说明

1、gradle-wrapper.properties文件

如下:

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https://services.gradle.org/distributions/gradle-6.5-bin.zip

最重要的是最后一行,运行别人的项目时必须检查的地方。因为别人的Gradle版本本地不一定有,本都没有的话就会开始漫长的下载,所以运行别人的项目时先把这里改成跟本地一致。当然也可能别人用的Gradle版本跟这里配置的不一致,但这种概略比较小。

2、proguard-rules.pro文件

没有手动配置混淆规则时,里面都是注释。那一般配置文件有哪些内容:

#指定代码的压缩级别
-optimizationpasses 5

#包名不混合大小写
-dontusemixedcaseclassnames

#不忽略非公共的库类
-dontskipnonpubliclibraryclasses

#优化/不优化输入的类文件
-dontoptimize

#预校验
-dontpreverify

#混淆时是否记录日志
-verbose

#混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

#忽略警告
-ignorewarning

#保护注解
-keepattributes *Annotation*

#保护反射的正常调用
-keepattributes Signature
-keepattributes EnclosingMethod

#不混淆哪些类
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService


#不混淆所有View的子类及其子类的get、set方法
-keep public class * extends android.view.View {
        public <init>(android.content.Context);
        public <init>(android.content.Context, android.util.AttributeSet);
        public <init>(android.content.Context, android.util.AttributeSet, int);
        public void set*(...);
        public *** get*();
}

#指定不混淆所有的JNI方法
-keepclasseswithmembernames class * {
    native <methods>;
}

#不混淆Activity中参数类型为View的所有方法
-keepclassmembers class * extends android.app.Activity {
       public void *(android.view.View);
}

#不混淆Parcelable和它的子类,还有Creator成员变量
-keep class * implements android.os.Parcelable {
      public static final android.os.Parcelable$Creator *;
}

#不混淆Serializable接口
-keepnames class * implements java.io.Serializable

#不混淆Serializable接口的子类中指定的某些成员变量和方法
-keepclassmembers class * implements java.io.Serializable {
        static final long serialVersionUID;
        private static final java.io.ObjectStreamField[] serialPersistentFields;
        !static !transient <fields>;
        !private <fields>;
        !private <methods>;
        private void writeObject(java.io.ObjectOutputStream);
        private void readObject(java.io.ObjectInputStream);
        java.lang.Object writeReplace();
        java.lang.Object readResolve();
}

#不混淆R类里及其所有内部static类中的所有static变量字段
-keepclassmembers class **.R$* {
        public static <fields>;
}

#如果有用到Gson解析包的,直接添加下面这几行就能成功混淆,不然会报错。
-keep class sun.misc.Unsafe { *; }
-keep class com.google.gson.examples.android.model.** { *; }

#如果有用到WebView的JS调用接口,需加入如下规则。
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
       public *;
}

#apk包内所有class的内部结构
-dump class_files.txt
#未混淆的类和成员
-printseeds seeds.txt
#列出从apk中删除的代码
-printusage unused.txt
#混淆前后的映射
-printmapping mapping.txt

#忽略某个类的警告
-dontwarn com.unionpay.**
#不混淆某个类和成员变量
-keep class com.unionpay.** { *; }

-dontwarn android.support.**
-dontwarn com.flurry.**
-dontwarn com.paypal.**
-dontwarn org.lucasr.**
-dontwarn org.android.agoo.ut.impl.**

根据需求配置,有些类混淆时会出问题,比如webview的某些方法等。

3、gradle.properties(Project Properties)

全局的属性配置文件

# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.

//默认编码格式
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8  

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn

//用androidx
android.useAndroidX=true   

# Automatically convert third-party libraries to use AndroidX

//迁移指向android.support.* 软件包的Java、XML、POM 和ProGuard 引用,更改它们以使其指向相应的androidx.*
android.enableJetifier=true   

//配置模块化的运行方式,singleModule=true表示每个模块都独立运行作为单独的apk,fasle标志作为module,被app模块依赖。
singleModule=false   (后面会用到)

4、settings.gradle文件

模块的列表
如果是写一个Gradle plugins模块(插件)需要把插件的incluede删掉

include ':app'   //模块
rootProject.name = "TestGradle"   //根项目名称,改这里会改项目名称

5、local.properties文件

本地配置,比如sdk,ndk等

//配置项目支持NDK
ndk.dir=/Users/ailian/sdk/ndk-bundle 
//配置项目支持SDK
sdk.dir=/Users/ailian/sdk

6、根目录的build.gradle文件

buildscript {   //gradle脚本执行所需仓库和依赖
    repositories {   //仓库
        google()
        jcenter()
    }
    dependencies {  //依赖
        classpath 'com.android.tools.build:gradle:3.0.0' //gradle插件版本
        

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

allprojects {  //项目需要的仓库
    repositories {
        google()
        jcenter()
    }
}

//task 运行会删掉build根文件夹
task clean(type: Delete) {
    delete rootProject.buildDir
}

7、module的build.gradle文件

1)apply plugin

声明依赖的插件,其中application的插件可以动态配置是以apk还是以library运行,如下

//根据是否独立运行,将模块作为apk还是module
if (singleModule.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

2)添加签名配置

在android闭包中配置

 signingConfigs {// 自动化打包配置
        release {// 线上环境
            keyAlias 'test'
            keyPassword '123456'
            storeFile file('test.keystore')
            storePassword '123456'
        }
        debug {// 开发环境
            keyAlias 'test'
            keyPassword '123456'
            storeFile file('test.keystore')
            storePassword '123456'
        }
    }

在buildTypes闭包中使用

buildTypes {// 生产/测试环境配置
        release {// 生产环境
            buildConfigField("boolean", "LOG_DEBUG", "false")//配置Log日志
            signingConfig signingConfigs.release//设置签名信息
            ...
        }
        debug {// 测试环境
            buildConfigField("boolean", "LOG_DEBUG", "true")//配置Log日志
            signingConfig signingConfigs.debug//设置签名信息
           ...
        }
    }

上面的代码还会生成一个配置参数,参数在Build.gradle文件中

image.png

通过BuildConfig.LOG_DEBUG可以直接取用。

3)配置目录指向

资源的配置,比如下面这种见过的写法

//资源配置
    sourceSets {
        main {
            //jni
            jni.srcDirs = []
            jniLibs.srcDirs = ['libs']
            //清单文件
            manifest.srcFile 'src/main/AndroidManifest.xml'
            //java文件
            java.srcDirs = ['src/main/java', '.apt_generated']
            //aidl
            aidl.srcDirs = ['src/main/aidl', '.apt_generated']
            //assets
            assets.srcDirs = ['src/main/assets']
            //资源文件(比如res外再添加res-main)
            res.srcDirs += [
                    'src/main/res-main'
            ]
        }
    }

4)多渠道包

除了debug,release可以额外增加渠道包的flavors(风味),比如:

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

//额外增加二个风味,paying免费版还是付费版,nation中文版还是国际版
flavorDimensions 'paying','nation'
productFlavors{
    free{   //免费版
        dimension 'paying'   //属于paying风味
        applicationId 'com.abc.test.free'
    }

    paid{   //付费版
        dimension 'paying'   //属于paying风味
        applicationId 'com.abc.test.paid'
    }

    chinese{   //中文版
        dimension 'nation'   //属于nation风味
        applicationId 'com.abc.test.chinese'
    }

    international{    //国际版
        dimension 'nation'   //属于nation风味
        applicationId 'com.abc.test.international'
    }
}

那么一共有多少种包呢?

image.png

根据需要新建各种文件夹做版本粒度控制,打包时main文件夹内的内容加上粒度文件夹的内容会被打包进去。

image.png

把这些包打出来,先看下build.gradle的打包部分的代码

android {
    signingConfigs {
        release {
            //多渠道打包的配置信息
            storeFile file("../test.jks")
            storePassword "123456"
            keyAlias "test"
            keyPassword "123456"
        }

        debug {
            //多渠道打包的配置信息
            storeFile file("../test.jks")
            storePassword "123456"
            keyAlias "test"
            keyPassword "123456"
        }
    }

    ...

    buildTypes {
        debug{
            signingConfig signingConfigs.debug  //配置打包的参数
        }
        release {
            signingConfig signingConfigs.release  //配置打包的参数
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    flavorDimensions 'paying','nation'
    productFlavors{
        free{
            dimension 'paying'
            applicationId 'com.abc.test.free'
        }

        paid{
            dimension 'paying'
            applicationId 'com.abc.test.paid'
        }

        chinese{
            dimension 'nation'
            applicationId 'com.abc.test.chinese'
        }

        international{
            dimension 'nation'
            applicationId 'com.abc.test.international'
        }
    }

    productFlavors.all {
            //批量修改,类似一个循序遍历
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
    }

    ...
}

打包出来

image.png

渠道包指定格式输出的代码略。

5)完整build.gradle文件

这份完整文件来自一篇博客作为参考,文件最后有附链接。

// 声明是Android程序,
//com.android.application 表示这是一个应用程序模块
//com.android.library 标识这是一个库模块
//而这区别:前者可以直接运行,后着是依附别的应用程序运行
apply plugin: 'com.android.application'

android {
    signingConfigs {// 自动化打包配置
        release {// 线上环境
            keyAlias 'test'
            keyPassword '123456'
            storeFile file('test.jks')
            storePassword '123456'
        }
        debug {// 开发环境
            keyAlias 'test'
            keyPassword '123456'
            storeFile file('test.jks')
            storePassword '123456'
        }
    }
    compileSdkVersion 27//设置编译时用的Android版本
    defaultConfig {
        applicationId "com.billy.myapplication"//项目的包名
        minSdkVersion 16//项目最低兼容的版本
        targetSdkVersion 27//项目的目标版本
        versionCode 1//版本号
        versionName "1.0"//版本名称
        flavorDimensions "versionCode"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"//表明要使用AndroidJUnitRunner进行单元测试
    }
    buildTypes {// 生产/测试环境配置
        release {// 生产环境
            buildConfigField("boolean", "LOG_DEBUG", "false")//配置Log日志
            buildConfigField("String", "URL_PERFIX", ""https://release.cn/"")// 配置URL前缀
            minifyEnabled false//是否对代码进行混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的规则文件
            signingConfig signingConfigs.release//设置签名信息
            pseudoLocalesEnabled false//是否在APK中生成伪语言环境,帮助国际化的东西,一般使用的不多
            zipAlignEnabled true//是否对APK包执行ZIP对齐优化,减小zip体积,增加运行效率
            applicationIdSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
            versionNameSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
        }
        debug {// 测试环境
            buildConfigField("boolean", "LOG_DEBUG", "true")//配置Log日志
            buildConfigField("String", "URL_PERFIX", ""https://test.com/"")// 配置URL前缀
            minifyEnabled false//是否对代码进行混淆
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的规则文件
            signingConfig signingConfigs.debug//设置签名信息
            debuggable false//是否支持断点调试
            jniDebuggable false//是否可以调试NDK代码
            renderscriptDebuggable false//是否开启渲染脚本就是一些c写的渲染方法
            zipAlignEnabled true//是否对APK包执行ZIP对齐优化,减小zip体积,增加运行效率
            pseudoLocalesEnabled false//是否在APK中生成伪语言环境,帮助国际化的东西,一般使用的不多
            applicationIdSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
            versionNameSuffix 'test'//在applicationId 中添加了一个后缀,一般使用的不多
        }
    }

    sourceSets {//目录指向配置
        main {
            jniLibs.srcDirs = ['libs']//指定lib库目录
        }
    }

    packagingOptions{//打包时的相关配置
        //pickFirsts做用是 当有重复文件时 打包会报错 这样配置会使用第一个匹配的文件打包进入apk
        // 表示当apk中有重复的META-INF目录下有重复的LICENSE文件时  只用第一个 这样打包就不会报错
        pickFirsts = ['META-INF/LICENSE']

        //merges何必 当出现重复文件时 合并重复的文件 然后打包入apk
        //这个是有默认值得 merges = [] 这样会把默默认值去掉  所以我们用下面这种方式 在默认值后添加
        merge 'META-INF/LICENSE'

        //这个是在同时使用butterknife、dagger2做的一个处理。同理,遇到类似的问题,只要根据gradle的提示,做类似处理即可。
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }

    productFlavors {
        wandoujia {}
        xiaomi {}
        _360 {}
    }

    productFlavors.all {
            //批量修改,类似一个循序遍历
        flavor -> flavor.manifestPlaceholders = [IFLYTEK_CHANNEL: name]
    }

    //程序在编译的时候会检查lint,有任何错误提示会停止build,我们可以关闭这个开关
    lintOptions {
        abortOnError false
        //即使报错也不会停止打包
        checkReleaseBuilds false
        //打包release版本的时候进行检测
    }

}

dependencies {
    //项目的依赖关系
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    //本地jar包依赖
    implementation 'com.android.support:appcompat-v7:27.1.1'
    //远程依赖
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    testImplementation 'junit:junit:4.12'
    //声明测试用例库
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

三、Gradle文件的统一管理

当模块变多,多份build.gradle难免会出现各种问题,比如依赖冲突,版本不一致等。那如何做统一管理,下面是二种方式,写法不固定重要的是思路。孰优孰劣,仁者见仁。

1、方式一

将build.gradle需要的配置做统一管理,在根目录创建gradle文件

image.png

这个文件的配置大致如下

//配置变量给下面的依赖用
def appcompat_version = "1.1.0"
def recyclerview = "1.1.0"
def rxjava = "2.2.8"
def rxandroid = "2.1.1"
def retrofitVersion = "2.8.1"


project.ext {
    android = [  //配置android的一些参数
                 compileSdkVersion: 30,
                 buildToolsVersion: "30.0.1",
                 applicationId    : "com.abc.abcde",
                 minSdkVersion    : 19,
                 targetSdkVersion : 30,
                 versionCode      : 1,
                 versionName      : "1.0"
    ]

    dependencies = [  //配置依赖的一些参数
                      //android-support
                      "appcompat"             : "androidx.appcompat:appcompat:${appcompat_version}",
                      "recyclerview"          : "androidx.recyclerview:recyclerview:${recyclerview}",

                      //rxjava
                      "rxjava"                : "io.reactivex.rxjava2:rxjava:${rxjava}",
                      "rxandroid"             : "io.reactivex.rxjava2:rxandroid:${rxandroid}",

                      // Retrofit
                      "retrofit"              : "com.squareup.retrofit2:retrofit:${retrofitVersion}",
                      "adapter-rxjava"        : "com.squareup.retrofit2:adapter-rxjava2:${retrofitVersion}",
                      "converter-gson"        : "com.squareup.retrofit2:converter-gson:${retrofitVersion}",
                      "logging-interceptor"   : "com.squareup.okhttp3:logging-interceptor:${okhttpLogInterceptorVersion}",
    ]
}

在根目录的build.gradle加上引用这个gradle文件的代码

apply from: "dependencies.gradle"

在module的build.gradle文件中使用

apply plugin: 'com.android.library'

android {
    compileSdkVersion rootProject.ext.android.compileSdkVersion
    buildToolsVersion rootProject.ext.android.buildToolsVersion

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

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles 'consumer-rules.pro'
    }

    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    dataBinding {
        enabled = true
    }
    compileOptions {
        sourceCompatibility 1.8
        targetCompatibility 1.8
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    //引用依赖
    implementation rootProject.ext.dependencies["appcompat"]
    implementation rootProject.ext.dependencies["rxjava"]

2、方式二

所有的module都引用同一份gradle文件,这一份文件包含了build.gradle需要的所有配置,所有module的依赖项也是一样的。每个module的build.gradle维护自己特有的属性,其他的都由同一份gradle文件来管理。

新建一个gradle文件

image.png

这个文件的配置如下

//配置各个module共用的插件
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'//kotlin语言使用注入框架,dataBinding都需要这个
apply plugin: 'androidx.navigation.safeargs.kotlin'//用于navigation传参的时候一种安全防护,非空,类型判断等。

android {
    //还是做一些基础的抽取管理
    compileSdkVersion compile_sdk_version
    buildToolsVersion build_tools_version

    defaultConfig {
        minSdkVersion min_sdk_verion
        targetSdkVersion target_sdk_version
        versionCode lib_version_code
        versionName lib_version_name

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles 'consumer-rules.pro'
    }

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


    //AS4 以上版本使用这个配置dataBinding
    buildFeatures {
        dataBinding = true
    }

    compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }
    //使用jetpack的组件,会要求jdk 1.8最好,有的时候会遇到报错,需要配置如下,避免target jvm 1.8的那个报错
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')

    //region 平台相关的基础库
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9"
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation("androidx.core:core-ktx:1.3.1")
    implementation 'androidx.fragment:fragment-ktx:1.2.4'
    implementation 'androidx.activity:activity-ktx:1.1.0'
    implementation "androidx.constraintlayout:constraintlayout:2.0.0-beta8"
    //endregion

    //<edit-folder desc="优秀第三方必备框架库">

    // Koin for Kotlin
    implementation "org.koin:koin-core:$koin_version"
    implementation "org.koin:koin-core-ext:$koin_version"
    // Koin for Androidx
    implementation "org.koin:koin-androidx-scope:$koin_version"
    implementation "org.koin:koin-androidx-viewmodel:$koin_version"
    implementation "org.koin:koin-androidx-fragment:$koin_version"
    implementation "org.koin:koin-androidx-ext:$koin_version"

    testImplementation "org.koin:koin-test:$koin_version"
    //</edit-folder>

    //region jetPack libs
    implementation 'androidx.lifecycle:lifecycle-livedata:2.2.0'
    implementation 'androidx.lifecycle:lifecycle-viewmodel:2.2.0'
    implementation 'androidx.lifecycle:lifecycle-runtime:2.2.0'
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
    kapt "androidx.lifecycle:lifecycle-common-java8:2.2.0"

    implementation 'androidx.room:room-runtime:2.2.5'
    implementation 'androidx.room:room-common:2.2.5'
    implementation 'androidx.room:room-ktx:2.2.5'
    kapt "androidx.room:room-compiler:2.2.5"

    implementation 'androidx.paging:paging-runtime:2.1.2'
    implementation 'androidx.paging:paging-runtime-ktx:2.1.2'
    implementation 'androidx.paging:paging-common:2.1.2'
    implementation 'androidx.paging:paging-common-ktx:2.1.2'

    implementation 'androidx.work:work-runtime:2.4.0'
    implementation 'androidx.work:work-runtime-ktx:2.4.0'

    //注意配置navigation版本号的时候,project下的build.gradle的class path也需要同步navigation的版本号配置
    implementation "androidx.navigation:navigation-ui:$navigation_version"
    implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
    implementation "androidx.navigation:navigation-fragment:$navigation_version"
    implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
    implementation "androidx.navigation:navigation-runtime:$navigation_version"
    //endregion
    ...

}

抽取的android的版本管理因为不多就直接放在根目录的build.gradle文件中

ext {
		kotlin_version = '1.4.10'
		compile_sdk_version = 29
		build_tools_version = '29.0.3'
		min_sdk_verion = 21
		target_sdk_version = 29

		lib_version_code = 1
		lib_version_name = "1.0.0"

		navigation_version = "2.2.1"//navigation 版本号,需要在dependencies和classpath保持一致
		koin_version = '2.1.6'//依赖注入框架
	}

所有的module在build.gradle文件中引用这个文件,并配置自己特有的属性即可

//引用dependencies.gradle
apply from: '../dependencies.gradle'

//根据是否独立运行,将模块作为apk还是module
if (singleModule.toBoolean()) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}


android {
    //from dependencies.gradle
    defaultConfig{
        //只有独立运行时候才需要applicationId
        if (singleModule.toBoolean()) {
            applicationId "com.abc.app.login"
        }
    }
}

dependencies {
    //依赖common模块
    api project(path: ':common')
}

参考博客

AndroidStudio之Gradle配置文件详解

史上最全Android build.gradle配置详解

--个人学习笔记