SDK开发中gradle的全局配置

前言

gradle统一入口版本管理的初衷是解决一个项目只要一个地方修改,各个有引用的模块便可以自动生效,从而达到了一个地方修改各个地方生效的好处,同时能保持gradle引用库版本的一致,特别适合在多module项目中统一管理。

如何新建一个config.gradle文件

先说明一下我是Mac环境和Window有那么一点区别,但是基本差不多。在根目录新建config.gradle文件, 并在项目的app\build.gradle 中引用它。

创建config.gradle.png
新建config文件.png
config.gradle.png

config.gradle中的配置

图中已经标注了步骤 ,按照上述步骤操作,你的全局gradle就已经配置好了,接下来看一下具体是怎么配置的。


 //config.gradle,ext:添加额外的属性
ext {
   //基础构建属性
   android = [
            compileSdkVersion   : 30,  // 编译sdk版本
            buildToolsVersion   :"30.0.1", //指定SDK构建工具的命令行版本,这个属性是可选的
            applicationId       :'com.example.myapplication', //唯一标识要发布的包。
            minSdkVersion       : 19, //最低安装版本
            targetSdkVersion    : 30,   //目标适配版本
            versionCode         : 1,
            versionName         : "1.0.0",
            ndkVersion          : "21.0.6113669"  //ndk版本配置
    ]

   //远程依赖版本
    dependent_Version = [
            appcompat_version: "1.3.0",
    ]

    //远程依赖
    dependencies = [
            "appcompat"              : "androidx.appcompat:appcompat:${dependent_Version["appcompat_version"]}",
            "appcompat-resources"    : "androidx.appcompat:appcompat-resources:${dependent_Version["appcompat_version"]}",

            "material"               : 'com.google.android.material:material:1.1.0',
            "constraintlayout"       : 'androidx.constraintlayout:constraintlayout:2.0.4',
            "navigation-fragment"    : 'androidx.navigation:navigation-fragment:2.2.2',
            "navigation"             : 'androidx.navigation:navigation-ui:2.2.2',

            "okio"                   : 'com.squareup.okio:okio:2.2.2',
            "okhttp"                 : 'com.squareup.okhttp3:okhttp:3.12.1',
            //集成 Bugly
            "crashreport"            : 'com.tencent.bugly:crashreport:latest.release',
            "nativecrashreport"      : 'com.tencent.bugly:nativecrashreport:latest.release',

    ]

    //签名配置
    sign=[
            keyAlias :'admin',
            keyPassword :'admin',
            storeFile :"/Users/Project/admin.keystore",
            storePassword: 'admin',
    ]
}

针对上面的config.gradle配置做一下说明,基本构建属性部分没什么可说的,常用的属性都已经填写上了。远程库依赖部分,我单独拆出去一个远程库版本,这样写的目的是为了统一相同版本号依赖好管理。

例如上面展示的appcompat库和appcompat-resources库。建议有同版本的库统一依赖到dependent_Version[],不同版本正常写到dependencies[]

根目录/build.gradle配置

根目录/build.gradle.png

//把配置好的全局文件加载进来,如果不加上这个配置app/build.gradle无法使用配置好的全局属性
apply from:"config.gradle" 

buildscript {
    repositories {  //配置远程仓库
        google()
        jcenter()
    }
    dependencies {  //配置构建工具

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

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

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

/**
 * 运行gradle clean时,执行此处定义的task任务。
 */
task clean(type: Delete) {
    delete rootProject.buildDir
}

app/build.gradle配置

app/build.gradle先发一份完整的配置,可供大家参考。然后按顺序把相关的配置拆出来单独进行讲解说明


apply plugin: 'com.android.application'  //表示该模块为应用程序模块,可以直接运行,打包得到的是.apk文件
//'com.android.library',表示该模块为库模块,只能作为代码库依附于别的应用程序模块来运行,打包得到的是.aar文件

def  buildConfig=rootProject.ext.android

/**
 * 定义时间类型格式,精确到毫秒
 */
def buildTime() {
    return new Date().format("yyyyMMddHHmmss", TimeZone.getTimeZone("GMT+08:00"))
}

android {
    compileSdkVersion buildConfig.compileSdkVersion
    buildToolsVersion  rootProject.ext.android.buildToolsVersion
    useLibrary 'org.apache.http.legacy' //HttpClient在Android5.0上无效,在Studio里面,可以通过使用useLibrary 'org.apache.http.legacy'配置进行编译

    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
        ndkVersion          rootProject.ext.android.ndkVersion

        multiDexEnabled     true    //多dex的支持
        flavorDimensions    "default"

        // 全局清单占位符配置
        manifestPlaceholders = [
                'UMENG_APPKEY' : '999888',
        ]

        //resValue "string", "facebook_app_id", "12sasdvg"

    }


    signingConfigs{ //签名配置

         debug { //开发环境
             keyAlias rootProject.ext.sign.keyAlias
             keyPassword rootProject.ext.sign.keyPassword
             storeFile file(rootProject.ext.sign.storeFile)
             storePassword rootProject.ext.sign.storePassword
         }

        release{ //正式环境
            keyAlias rootProject.ext.sign.keyAlias
            keyPassword rootProject.ext.sign.keyPassword
            storeFile file(rootProject.ext.sign.storeFile)
            storePassword rootProject.ext.sign.storePassword
        }

        configAll {
            keyAlias rootProject.ext.sign.keyAlias
            keyPassword rootProject.ext.sign.keyPassword
            storeFile file(rootProject.ext.sign.storeFile)
            storePassword rootProject.ext.sign.storePassword
        }

    }

    buildTypes {  // 构建项目类型

        debug {
            debuggable true  // 是否支持断点调试
            jniDebuggable true   //是否可以调试NDK代码
            zipAlignEnabled false     // 压缩对齐开关
            shrinkResources false  // 移除无用的资源
            minifyEnabled false      //是否开启代码混淆
            signingConfig signingConfigs.debug   // 设置签名信息
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的规则文件
            buildConfigField('boolean', 'LOG_SHOW', 'true') // 日志打印开关
            buildConfigField('String', 'BUGLY_APPID', '"0def765219"') //bugly key
            ndk {
                abiFilters 'armeabi-v7a'
            }

            // debug版本清单占位符配置
//            manifestPlaceholders = [
//                    'UMENG_APPKEY' : '111222',
//            ]

            resValue "string", "facebook_app_id", "aaabbb"
        }

        release {
            debuggable   false // 是否支持断点调试
            jniDebuggable false   //是否可以调试NDK代码
            zipAlignEnabled true     // 压缩对齐开关
            shrinkResources true  // 移除无用的资源
            minifyEnabled true      //是否开启代码混淆
            signingConfig signingConfigs.release   // 签名信息配置
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定混淆的规则文件
            buildConfigField('boolean', 'LOG_SHOW', 'false') // 日志打印开关
            buildConfigField('String', 'BUGLY_APPID', '"0def711122s2"') //bugly key
            ndk {
                // armeabi:万金油架构平台(占用率:0%)
                // armeabi-v7a:曾经主流的架构平台(占用率:10%)
                // arm64-v8a:目前主流架构平台(占用率:95%)
                abiFilters 'armeabi-v7a', 'arm64-v8a'
            }

            // release版本清单占位符配置
//            manifestPlaceholders = [
//                    'UMENG_APPKEY' : '2223333',
//            ]
            resValue "string", "facebook_app_id", "bbbccc"
        }
    }

    productFlavors {

        Google {
        }

        FaceBook {
        }

        Twitter {
        }
    }

    /**
     *  该属性多用于第三方库文件重复或者冲突
     */
    packagingOptions {
        exclude 'META-INF/*******' //剔除这个包下制定目录下的所有文件(不会移除签名信息)
        doNotStrip '*/mips/*.so'   //剔除mips下的所有SO架构
        pickFirst "lib/mips/libil2cpp.so"  //匹配到多个相同文件,只提取第一个
        merge 'META-INF/LICENSE'    //当出现重复文件时 合并重复的文件 然后打包入apk
    }


    compileOptions {  //编译选项
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }


    aaptOptions { //aapt打包工具,会映射到com.android.build.gradle.internal.dsl.aaptOptions类
        noCompress '.unity3d', '.ress', '.resource', '.obb'    //不对左侧文件类型压缩
        ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~"  //忽略文件类型
    }

    lintOptions {  //lint选项
        checkReleaseBuilds false  //表示在进行Release构建时不再进行Lint检查
        abortOnError false   //检查到错误后继续编译,不取消当前的构建任务。
    }

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

    /**
     * 重新命名apk名称  格式:帝国游戏_v1_20210616112133_debug.apk
     * 命名规范 应用名-版本号-毫秒时间-开发环境.apk
     */
    android.applicationVariants.all {
        variant ->
            variant.outputs.all {
                outputFileName = "帝国游戏_"+"v${variant.versionCode}_"+"${buildTime()}_"+variant.name+".apk"
            }
    }


    /**
     * 重新格式重命名aar文件  格式:lib_plugin_bytedance-debug_20210422130607.aar
     * 这个只能在 apply plugin: 'com.android.library' build.gradle中添加,不然报错
     */

//    android.libraryVariants.all { variant ->
//        variant.outputs.all {
//            outputFileName = "lib_plugin_bytedance-"+ variant.name+"_${buildTime()}.aar"
//        }
//    }


}

dependencies {
    // 依赖本地 libs 目录下所有的 jar 和 aar 包
    implementation fileTree(include: ["*.jar", '*.aar'], dir: "libs")

    implementation rootProject.ext.dependencies["appcompat"]
   // print("获取到信息:"+rootProject.ext.dependencies["appcompat"])
    implementation rootProject.ext.dependencies["appcompat-resources"]
    implementation rootProject.ext.dependencies["material"]
    implementation rootProject.ext.dependencies["constraintlayout"]
    implementation rootProject.ext.dependencies["navigation-fragment"]
    implementation rootProject.ext.dependencies["navigation"]

    //集成 Bugly
    implementation rootProject.ext.dependencies["crashreport"] //其中latest.release指代最新Bugly SDK版本号,也可以指定明确的版本号,例如2.1.9
    implementation rootProject.ext.dependencies["nativecrashreport"] //其中latest.release指代最新Bugly NDK版本号,也可以指定明确的版本号,例如3.0

}

基本配置项

配置好config.gradle 后,开始引用一下全局gradle的属性。rootProject.ext.android等同于取config.gradle配置里的ext属性下的android字段。上面定义了一个buildConfig变量是向大家演示一下另一种写法,在compileSdkVersion 属性中做了展示。

至于目的吗?看着那么长一串不爽,简化一下,同学们可根据自己的喜好进行编写,结果是一样的就是写法不同而已。接下来的全局远程依赖部分和全局签名也是同理不做说明。基本配置部分没什么好说的,就这样我继续往下说。

signingConfigs属性配置

这部分是配置一些签名模式的 ,其中包含默认的debug(开发测试)和release(对外发布)两种模式。在这两个基础上添加了一个configAll的签名模式。

我先说一下默认的两种模式,从规范角度出发,开发中基本会有测试版本和发布版本,它们分别对应一个签名,方便管理和区分。

但有另外一种情况,例如我们接入Google Play,这个SDK有点特别 !!!怎么特别呢? 它是绑定包名和签名文件的。包名不对、签名文件MD5等信息对不上,支付都拉不起来。

假如你运行debug模式,用的是系统默认的签名(非Google后台记录的签名),那么恭喜你支付一定是拉不起来的。针对这种情况增加了第三个属性配置, configAll 就是为了处理这种情况。通俗的说configAll属性就是debug和release共用一个签名(针对google情况)。

  //默认情况下的config.gradle 签名配置
    sign=[
            keyAlias :'admin',
            keyPassword :'admin',
            storeFile :"/Users/Project/admin.keystore",
            storePassword: 'admin',
    ]

观察一下,下面的写法与最开始的签名配置有很大的不同。先说一下config.gradle部分,增加了一个新的属性signConfigs,它的加入是为了configAll属性而生。

也就是debug和release共用这个签名,这个签名取自sign字段里面的属性集合,很灵活。只要把需要的配置都加上,随你取签名属性集。例如configAll要上架Google 写法就可以改成:signConfigs=sign["google"]

  //改版本后的config.gradle 签名配置

 sign=[
      "google" :[
                    keyAlias :'admin1',
                    keyPassword :'admin1',
                    storeFile :"/Users/Project/admin1.keystore",
                    storePassword: 'admin1',
                 ],
    "bytedance":[
                    keyAlias :'admin2',
                    keyPassword :'admin2',
                    storeFile :"/Users/Project/admin2.keystore",
                    storePassword: 'admin2',
                 ],
 ]

   //获取固定签名属性配置
    signConfigs=sign["bytedance"]

下面代码主要说debug和release 模式,两种模式都分别配置了不同的签名。这个配置偏向于,debug模式签名做测试。正式模式用release签名。大家可以根据自己的需求做一下调整,写法上不局限于SDK。

//    app/build.gradle

signingConfigs{ //签名配置

         debug { //开发环境
             keyAlias rootProject.ext.sign["bytedance"]["keyAlias"]
             print("keyAlias:========== "+rootProject.ext.sign["bytedance"]["keyAlias"]+" && ")
             keyPassword rootProject.ext.sign["bytedance"]["keyPassword"]
             print("keyPassword:========== "+rootProject.ext.sign["bytedance"]["keyAlias"]+" && ")
             storeFile file(rootProject.ext.sign["bytedance"]["storeFile"])
             print("debug签名文件路径:========== "+rootProject.ext.sign["bytedance"]["storeFile"]+" && ")
             storePassword rootProject.ext.sign["bytedance"]["storePassword"]
             print("storePassword:=========="+rootProject.ext.sign["bytedance"]["storePassword"]+" && ")
         }

        release{ //正式环境
            keyAlias rootProject.ext.sign["google"]["keyAlias"]
            print("keyAlias:========== "+rootProject.ext.sign["google"]["keyAlias"]+" && ")
            keyPassword rootProject.ext.sign["google"]["keyPassword"]
            print("keyPassword:========== "+rootProject.ext.sign["google"]["keyAlias"]+" && ")
            storeFile file(rootProject.ext.sign["google"]["storeFile"])
            print("release 签名文件路径:========== "+rootProject.ext.sign["google"]["storeFile"]+" && ")
            storePassword rootProject.ext.sign["google"]["storePassword"]
            print("storePassword:=========="+rootProject.ext.sign["google"]["storePassword"]+" && ")
        }

        configAll { //通用
            keyAlias rootProject.ext.signConfigs.keyAlias
            keyPassword rootProject.ext.signConfigs.keyPassword
            storeFile file(rootProject.ext.signConfigs.storeFile)
            storePassword rootProject.ext.signConfigs.storePassword
        }
    }

buildTypes构建类型

这部分主要说默认的两种模式,debug模式主要用于代码和日志的分析,不会发布到线上给用户使用,配置的属性偏向于排查 和定位作用。release是要发布线上给用户使用,所以属性配置的很正式,关闭掉了无用的信息。

注释比较齐全不做多余说明。建议例如签名,测试环境用signingConfigs.debug 正式环境用signingConfigs.release,直观、清晰明了。

BuildConfig.java.png

介绍一下buildConfigField属性,它会在运行时创建debug或者release的BuildConfig.java 用法很灵活,例如debug需要打印日志,release需要关闭日志 。

LOG_SHOW就是app/build.gradle 里的buildConfigField('boolean', 'LOG_SHOW', 'true') 属性配置,debug模式等于true,release等于false。下面代码做一下逻辑区分,避免了重要日志输出到线上,供不法分子做不利的事情。

public class LogUtils {

    public  static   boolean   isShowLog= BuildConfig.LOG_SHOW;

    public static void info(String tag, String message) {
        if (isShowLog) {
            Log.i(tag, message);
        }
    }
}

再来介绍一下 manifestPlaceholders 属性配置,简单说就是对清单文件做配置。开发中很多时候我们会遇到这种场景,比如说:在用到一个第三方sdk,但是这个sdk并没有区分开发环境和线上环境,这时候我们就可能会申请两个不同的key标识,而且很多key标识都只能在androidmanifest里面配置。

所以每次上线生成apk就必须手动去更改key标识,如果渠道版本少还好,如果多了是个很要命的事情。拿友盟SDK举个例子,集成友盟sdk 在清单文件一定会配置meta-data属性,用下面的写法你会发现配置不同环境的参数,在不同环境展示的也不同。这种方式避免了频繁手动改key值,一次配置好一劳永逸。方便快捷效率还高。

如果所有模式共用一个友盟KEY 建议配置默认defaultConfig{}属性内。manifestPlaceholders属性不止友盟sdk这种需求,不同环境更改应用名字同样适用。我就不做举例,学会举一反三很重要。

buildTypes
  debug {
    manifestPlaceholders = [
            // debug版本清单占位符配置
            'UMENG_APPKEY' : '111222',
       ]
  }

  release {
    manifestPlaceholders = [
            // debug版本清单占位符配置
            'UMENG_APPKEY' : '2223333',
       ]
  }


//清单文件配置

   
        


debug友盟配置.png
release友盟配置.png

接着介绍一下resValue属性,这个属性跟manifestPlaceholders类似,主要是对res/values/Strings.xml做处理的。如果不想在Strings.xml直接写属性,可以通过resValue方式添加进去。可以在不同维度上做改变,特别灵活。用法如下:

buildTypes
  debug {
       resValue "string", "facebook_app_id", "aaabbb"
  }


  release {
        resValue "string", "facebook_app_id", "bbbccc"
  }

我只把release配置展示出来了,debug 得到的字符串是 aaabbb,这里我不做演示了。 如果全局共用一个resValue属性建议写在默认defaultConfig{ resValue "string", "facebook_app_id", "zzzaaaa"}属性内,在任意模式下 得到的字符串都是zzzaaaa

release效果图.png
生成配置.png

productFlavors变体配置

这里做个简单描述,加上配置后会生成多个apk,例如生成Google包可以在google{}属性里面做配置,配合着debug和release 加上、上面说过的属性自由组合,会有意想不到效果。这productFlavors变体属性和buildTypes属性类似。

productFlavors.png

APK重新命名

做一下简单说明:相比传统默认的debug.apk 或者release.apk方式命名,重新命名带好的好处直观明了,多个包的看着不乱也规范,可以给我们开发中减少不少麻烦。

如何用: 这个属性只能在apply plugin: 'com.android.application' 中使用,执行gradle命令或者build项目都可以生成对应的文件。

  /**
     * 重新命名apk名称  格式:帝国游戏_v1_20210616112133_debug.apk
     * 命名规范 应用名-版本号-毫秒时间-开发环境.apk
     */
    android.applicationVariants.all {
        variant ->
            variant.outputs.all {
                outputFileName = "帝国游戏_"+"v${variant.versionCode}_"+"${buildTime()}_"+variant.name+".apk"
            }
    }
重命名APK.png

AAR重新命名

如何用: 这个属性只能在apply plugin: 'com.android.library' 中使用,执行gradle命令或者build项目都可以生成对应的文件。

    // 重新格式重命名aar文件  格式:lib_plugin_bytedance-debug_20210422130607.aar

    android.libraryVariants.all { 
        variant ->
          variant.outputs.all {
                outputFileName = "lib_plugin_bytedance-"+ variant.name+"_${buildTime()}.aar"
       }
    }

文章末尾

本文偏向于记录作者工作中用到的技术部分,那一次忘了会以笔记的形式回顾。内容可能略微啰嗦,偏向基础和 详细说明。各位看官多多见谅 !!!

你可能感兴趣的:(SDK开发中gradle的全局配置)