• [Android] 配置build.gradle 动态传参


    (1)一个Android工程中有一个build.gradle是负责Project范围的,而Module中又有各自的build.gradle是专门负责模块的。

    (2)在Gradle中Task是一等公民,通过gradlew + task名 可以直接执行指定Task,例如下面的命令就是执行:task releaseAutoBLForAar

    gradlew releaseAutoBLForAar

    (3)在defaultConfig中可以自定义变量名,编译时可以在Java代码中引用到:

    defaultConfig {
            applicationId "com.test"
            minSdkVersion 15
            targetSdkVersion 23
            versionCode 5
            versionName 1.1.0
            buildConfigField("String", "API_HOST", "${API_DEV_HOST}")
    }

      这里面的API_HOST是String型的(第三个参数是表示传值),可以看到Java代码生成,这样就能建立起代码与配置之间的桥梁:

    public final class BuildConfig {
              public static final boolean DEBUG = Boolean.parseBoolean("true");
              public static final String APPLICATION_ID = "com.test";
              public static final String BUILD_TYPE = "debug";
              public static final int VERSION_CODE = 6;
              public static final String VERSION_NAME = "1.1.1";
              // Fields from default config.
              public static final String API_HOST = "http://test.api.cn";
    }

    (4)通过 buildTypes 可以配置不同的任务参数

    buildTypes {
        release {       /* 线上环境 */
            buildConfigField "boolean", "LOG_DEBUG", "false"    // 不显示Log
            buildConfigField "String", "API_HOST", "${API_RELEASE_HOST}"    //API Host
            minifyEnabled true                      //是否混淆
            zipAlignEnabled true                    //是否设置zip对齐优化
            shrinkResources true                    // 移除无用的resource文件
            signingConfig signingConfigs.release    //签名
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        preRelease {    /* 预发环境 */
            buildConfigField "boolean", "LOG_DEBUG", "false"    // 不显示Log
            // 。。。
        }
        debug {         /* 本地开发环境 */
            minifyEnabled false
        }
        beta {          /* 测试环境 */
            buildConfigField "boolean", "LOG_DEBUG", "true"     // 显示Log
            // 。。。
        }
    }

    flavorDimensions "default"  // “变种”维度,必不可少
    productFlavors {        // 渠道包“变种”配置
      black {
      }
      yellow {
      }
    }

       可以通过AndroidStudio的Gradle面板看到多个编译任务,原来默认只有assembleDebug,现在就多了assembleBeta、assemblePreRelease、assembleRelease,双击即可执行。

    (4.1)在buildTypes的基础上,增加productFlavors “风味”来打渠道包。

      增加了productFlavors之后会与所有buildTypes进行一一组合,形成各个assemble类型。

      当执行 ./gradlew assemble 时,就会生成app-black-debug.apk、app-black-beta.apk、app-black-prerelease.apk、app-black-release.apk、app-yellow-debug.apk。。。等八种Apk;

      当执行 ./gradlew assembleDebug 时,就会生成app-black-debug.apk、app-yellow-debug.apk 两种Apk;

      当执行 ./gradlew assembleYellow 时,就会生成app-yellow-debug.apk、app-yellow-beta.apk、app-yellow-prerelease.apk、app-yellow-release.apk 四种Apk;

      当执行 ./gradlew assembleYellowDebug 时,就会生成 app-yellow-debug.apk 一种Apk;

    通过上面的例子可以看出规律,gradle 会把 buildType 和productFlavors 组合打包——通过配置productFlavots去进行多渠道打包,bulidType 控制着打出的包是debug 类型还是release类型。

    TIPS:gradle命令太长可以用首字母缩写来快捷调用,例如:./gradlew assembleRedRelease 就可以用 ./gradlew aRR 代替。不过如果有首字母重名的则会报错。

    (5)如何通过Gradle动态配置不同的AndroidManifest.xml 变量内容呢?通过自定义manifestPlaceholders 属性值。

      首先在AndroidManifest.xml 文件中指定要使用Gradle动态配置值${TALKING_DATA_APP_ID}:

        <!--TalkingData 配置-->
        <meta-data
            android:name="TD_APP_ID"
            android:value="${TALKING_DATA_APP_ID}" />

       可以在build.gradle中配置一个特别的变量属性:

    def TEST_TALKING_DATA_APP_ID = "6E5389EAD0C2C2CFB7B379701F6D2BA8"
    
    defaultConfig {
        applicationId "com.test"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 5
        versionName 1.1.0
        buildConfigField("String", "API_HOST", "${API_DEV_HOST}")
        manifestPlaceholders = [
                /* talkingData 测试环境 */
                TALKING_DATA_APP_ID: "${TEST_TALKING_DATA_APP_ID}"   /* 可以新增多个键值对,表示变量与对应的值 */
        ]
    }

       同理,我们可以在buildTypes中分别指定release、debug等配置的manifestPlaceholders 来达到不同的配置效果。 

    (6)如何在build.gradle中动态获取参数选项?通过 project.hasProperty('VERSION_CODE') 的形式来获取动态传参。

    defaultConfig {
        applicationId "com.ixwork"
        minSdkVersion 15
        targetSdkVersion 23
        //关键看这两行
        versionCode project.hasProperty('VERSION_CODE') ? Integer.parseInt(VERSION_CODE) : DEF_VERSION_CODE
        versionName project.hasProperty('VERSION_NAME') ? VERSION_NAME : "${DEF_VERSION_NAME}"
        buildConfigField("String", "API_HOST", "${API_DEV_HOST}")
    }

     (7)怎么传参呢?通过-PVAR_NAME=VAR_VALUE 的形式,其中-P就是加参数,例如:

    gradle clean assembleBeta -PVERSION_CODE=5 -PVERSION_NAME=1.1.1 -POUT_PUT_DIR=/home/user/Desktop -PFILE_NAME=test.apk  
    // 这里面一个小细节很重要,执行gradle任务时之前加一个clean清除一下结果,可以有效防止编译过程中误报错误。比如关闭了某个宏导致某些class文件不再被编译,但是可能由于旧的信息残留导致报错提示找不到class

     (8)怎么设置APP工程使用一个aar库呢?两步走:(1)设置本地仓库地址;(2)设置依赖文件名称和扩展名。

    dependencies {
        implementation fileTree(include: ['*.jar'], dir: 'libs')
        implementation 'com.android.support:appcompat-v7:26.1.0'
        implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    //    implementation project(':testjni')        // 这一句是用来设置工程依赖的,如果设置了直接依赖那么就好比就是同一个工程内了,直接import类使用即可
    
        compile (name:'testjni-debug', ext:'aar')   // 这一句是用来设置工程依赖某个具体aar包的,name字段填写包名,ext字段填写扩展名
    }

       如果是初始工程这么设置一下的话,编译会报错说找不到这个testjni-debug.arr,原因是存放这个文件的“仓库”路径并没有被加入到工程内,需要我们设置一下仓库地址(假设存在aar文件的路径是app/libs目录):

    allprojects {
        repositories {
            google()
            jcenter()
    
            flatDir {dirs '../app/libs'}       // 在整个工程的build.gradle 中仓库配置此字段
        }
    }

     (9)怎么理解一个task的内容?举几个很实用的小例子来看看:

    task clearOutput(type:Delete){    // 删除任务,内容就是删除两个目录
        delete 'build_output'
        delete '../app/libs'
    }
    
    task taskJar(type:Jar, dependsOn:"assembleRelease" ) {    // 这个Jar包的任务依赖于assembleRelease(系统的Release配置任务)意思就是相当于执行这个任务了,并且还附加了下面的逻辑步骤
        from 'build/intermediates/classes/release/'        // 源路径
        destinationDir = file('build_output/libs')         // 目标路径
    }
    
    task releaseOutput(type:Copy, dependsOn: [clearOutput, taskJar]) {    // 依赖于两个任务,相当于要依次执行完这两个任务,之后再拷贝文件(文件列表如下描述)
        from('libs') {
            include '*.jar','armeabi-v7a/lib*.so'
        }
        into ('build_output/libs')
    }
    
    task releaseOutputAar(type:Copy, dependsOn:[clearOutput, "assembleRelease"]){    // 依赖于两个任务,之后拷贝,拷贝的目标可以是多个,连续执行
        from('build/outputs/aar') {
            include 'testjni-release.aar'
        }
        into ('build_output')
        into ('../app/libs')
    }

     (10)【坑】有一点要理解深入点:一旦配置了externalNativeBuild,那么执行以及依赖assembRelease/Debug的任务可就都会编译打包so了!不配置就只会编译打包Java部分。

  • 相关阅读:
    编译错误总结。
    9.7
    9.5
    9.6
    9.4
    9.3
    FutureTask取结果超时代码小测试
    java concurrent包常用类小结
    java Nio零散知识点整理
    java进阶教程unit_2java常用类(2)
  • 原文地址:https://www.cnblogs.com/kuliuheng/p/9454280.html
Copyright © 2020-2023  润新知