管理我们的 gradle 依赖

现在 android 开发中对于 gradle 也是很多技巧的,简单的有统一管理依赖及其版本号,复杂一些的涉及到 gradle task,比如 apk 重命名,渠道包配置,buildTypes 编译模式中配置不同的参数,如 debug 和 release 配置不同的baseUrl,最难的是自定义 gradle plugin 脚本,去执行诸如统一图片压缩,打包等

我对 gradle 的了解也有限,但是还是要总结一下

这里我们对 gradle 进行以下几个方面的操作:

本文项目地址:BW_Libs

一些 gradle 的知识点,先暂时放在这里:


1. 统一管理远程依赖

我们在根目录创建一个 config.gradle 文件,.gradle 文件,我们可以看成 gradle 脚本。然后我们在这个 config.gradle 写项目中需要的远程依赖,然后在根项目的 build.gradle 中引用我们写的 config.gradle 这个脚本就成了,大家注意写法:

1.1 创建 config.gradle 文件
1.2 在 config.gradle 文件中书写依赖
//第三方依赖库和版本号管理
def versions = [:]

versions.support = "26.1.0"

versions.rxjava = "2.1.10"
versions.rx_android = "2.0.2"
versions.retrofit = "2.4.0"
versions.okhttp3 = "3.4.1"
versions.gson = "2.4.0"


ext {

    android = [
            compileSdkVersion: 26,
            buildToolsVersion: '26.0.2',
            minSdkVersion    : 19,
            targetSdkVersion : 26,
            applicationId    : 'com.bloodcrown.bw',
            versionCode      : 1,
            versionName      : '1.0',
            //            multiDexEnabled  : true
    ]

    signConfigs = [
            'storeFile'    : 'sign.jks',
            'storePassword': '123456',
            'keyAlias'     : 'sign',
            'keyPassword'  : '123456'
    ]

    java = [
            'javaVersion': JavaVersion.VERSION_1_8
    ]

    dependence = [

            // 官方
            'appcompatv7'            : "com.android.support:appcompat-v7:$versions.support",
            'supportv4'              : "com.android.support:support-v4:$versions.support",
            'design'                 : "com.android.support:design:$versions.support",
            'recyclerview'           : "com.android.support:recyclerview-v7:$versions.support",

            // rxjava2
            'rxjava'                 : "io.reactivex.rxjava2:rxjava:$versions.rxjava",
            'rxandroid'              : "io.reactivex.rxjava2:rxandroid:$versions.rx_android",

            // retrofit2
            'retrofit'               : "com.squareup.retrofit2:retrofit:$versions.retrofit",
            'gson'                   : "com.squareup.retrofit2:converter-gson:$versions.gson",
            'retrofitAdapter'        : "com.squareup.retrofit2:adapter-rxjava2:$versions.retrofit",

            // okhttp3
            'okhttp3'              : "com.squareup.okhttp3:okhttp:$versions.okhttp3",
            'http3LoggingInterceptor': "com.squareup.okhttp3:logging-interceptor:$versions.okhttp3",

    ]
}
1.3 根项目 build.gradle 引用 config.gradle 脚本
// Top-level build file where you can add configuration options common to all sub-projects/modules.

// 引入 config.gradle  脚本
apply from: this.file( "config.gradle" )


//引入文件
//apply from: this.file('common.gradle')
buildscript {
    ext.kotlin_version = '1.2.71'
    ext.recyclerview_version = '26.1.0'
    ext.gradle_version = '3.0.1'

    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.2.5'
        classpath "com.android.tools.build:gradle:$gradle_version"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

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

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'http://repo1.maven.org/maven2' }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}
1.4 使用 config.gradle 脚本中的依赖


apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

//apply from: rootProject.file( "config.gradle" )

android {

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

    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

        vectorDrawables.useSupportLibrary = true
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    dataBinding {
        enabled = true
    }

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

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

    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'

    implementation rootProject.ext.dependence.design
    implementation rootProject.ext.dependence.appcompatv7
    implementation rootProject.ext.dependence.recyclerview

    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
    kapt "com.android.databinding:compiler:$rootProject.ext.gradle_version"
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
    implementation project(':basecomponents')

    // retrofit 依赖
    implementation rootProject.ext.dependence.rxandroid
    implementation rootProject.ext.dependence.rxjava
    implementation rootProject.ext.dependence.retrofit
    implementation rootProject.ext.dependence.gson
    implementation rootProject.ext.dependence.retrofitAdapter
    implementation rootProject.ext.dependence.http3LoggingInterceptor
    implementation rootProject.ext.dependence.okhttp3
}

2. 提取所有 module gradle 公共配置项 common.gradle

上面我们使用 config.gradle 记录统一从 module 抽取出来的远程依赖,做成公共的一份再由 module 各自选取其中的依赖,然后我们在 config.gradle 中改远程依赖的版本号就可以在所有的 module 都生效了,这就是 java 中抽象封装的思想,难度是 gradle 语言上手不友好,自动提示出来的不是我们要的, 很难写

那么现在我们继续深入发挥这个 抽象封装 的思路,每个 module 中都有相同的配置项,我们把这个抽取出来,还是统一写到 common.gradle 中,然后每个 module 都依赖这个 common.gradle 即可,和 config.gradle 区别是,config.gradle 根目录 .gradle 引入就行了, common.gradle 需要所有的 module 都引用一份

common.gradle 中的依赖和配置也是要引用 config.gradle 的

2.1 创建 config.gradle 文件
2.2 书写 common.gradle
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

//kapt {
//    arguments {
//        arg("moduleName", project.getName())
//    }
//}

android {

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

    defaultConfig {

        minSdkVersion rootProject.ext.android.minSdkVersion
        targetSdkVersion rootProject.ext.android.targetSdkVersion

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

        vectorDrawables.useSupportLibrary = true

//        multiDexEnabled true

        ndk {
            abiFilters 'armeabi', 'x86'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    dataBinding {
        enabled = true
    }

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

dependencies {

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

    testImplementation rootProject.ext.dependence.junit
    androidTestImplementation rootProject.ext.dependence.runner
    androidTestImplementation rootProject.ext.dependence.espresso
    implementation rootProject.ext.dependence.multidex

    implementation rootProject.ext.dependence.kotlinStdlibJdk8
    implementation rootProject.ext.dependence.kotlinReflect
    kapt rootProject.ext.dependence.databinding

}
repositories {
    mavenCentral()
}
2.3 module 引入 common.gradle 依赖

app module:

apply plugin: 'com.android.application'

apply from:rootProject.file('common.gradle')

android {

    defaultConfig {

        applicationId rootProject.ext.android.applicationId
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName
    }

    signingConfigs {

        //release版的签名配置信息
        release {
            storeFile file(rootProject.ext.signConfigs.storeFile)
            storePassword rootProject.ext.signConfigs.storePassword
            keyAlias rootProject.ext.signConfigs.keyAlias
            keyPassword rootProject.ext.signConfigs.keyPassword
        }
    }

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

dependencies {

    implementation project(':basecomponents')
    implementation project(':baselib')
    implementation project(':common_repositroy')

    implementation rootProject.ext.dependence.design
    implementation rootProject.ext.dependence.appcompatv7
    implementation rootProject.ext.dependence.recyclerview
    implementation rootProject.ext.dependence.constraintLayout

    // retrofit 依赖
    implementation rootProject.ext.dependence.rxandroid
    implementation rootProject.ext.dependence.rxjava
    implementation rootProject.ext.dependence.retrofit
    implementation rootProject.ext.dependence.gson
    implementation rootProject.ext.dependence.retrofitAdapter
    implementation rootProject.ext.dependence.http3LoggingInterceptor
    implementation rootProject.ext.dependence.okhttp3
}

其他 module:

apply plugin: 'com.android.library'
apply from:rootProject.file('common.gradle')

android {

    defaultConfig {
    }

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

}

dependencies {

    implementation project(':baselib')

    implementation rootProject.ext.dependence.appcompatv7

    // retrofit 依赖
    implementation rootProject.ext.dependence.rxandroid
    implementation rootProject.ext.dependence.rxjava
    implementation rootProject.ext.dependence.retrofit
    implementation rootProject.ext.dependence.gson
    implementation rootProject.ext.dependence.retrofitAdapter
    implementation rootProject.ext.dependence.http3LoggingInterceptor
    implementation rootProject.ext.dependence.okhttp3
}

这样每个 module 只关心自己的需要的特殊依赖,配置就行,app moule 中还是有很多配置需要写的,这些配置涉及 app 打包等,所以不适合写进公共配置


gradle 补充

其实我们的 app 若不是很复杂的话或是大家嫌上面麻烦的话,还有一种更简单的写法,当然不是那么正式了

app 构建时在根目录提供了一个 gradle.properties 文件,这个 gradle.properties 就是提供书写 gradle 参数的地方,使用起来也很简单,直接调名字即可

apply plugin: 'com.android.library'

android {
    lintOptions {
        abortOnError false
    }

    compileSdkVersion Integer.parseInt(ANDROID_COMPILE_SDK_VERSION)
    buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION

    defaultConfig {
        minSdkVersion Integer.parseInt(ANDROID_MIN_SDK_VERSION)
        targetSdkVersion Integer.parseInt(ANDROID_BUILD_TARGET_SDK_VERSION)
        versionCode Integer.parseInt(APP_VERSION_CODE)
        versionName project.APP_VERSION_NAME
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
}

ext {
    supportLibraryVersion = project.ANDROID_SUPPORT_LIBRARY_VERSION
}

dependencies {
    testImplementation 'junit:junit:4.12'
    implementation "com.android.support:appcompat-v7:${supportLibraryVersion}"
    implementation "com.android.support:design:${supportLibraryVersion}"
}

// Place it at the end of the file
apply from: 'install_lib.gradle'
apply from: 'bintray_lib.gradle'

3. 修改资源文件目录

这个需求在多渠道打包或是插件化时常用,比如不同渠道包 icon 图标不同,切换子 module 类型

看下面的例子

3.1 切换 module 类型
android {
    sourceSets {
        main {
            if(isDebug.toBoolean()) {
                manifest.srcFile 'src/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/release/AndroidManifest.xml'
            }
        }
    }
}
3.2 修改 java 文件路径
android {
    // ...
    sourceSets {
        debug {
            java.srcDirs = ['src/main/java', 'src/debug/java']
        }
        release {
            java.srcDirs = ['src/main/java', 'src/release/java']
        }
    }
}
3.3 修改 module 依赖

和 3.2 一样,我们在不筒的 buildType 编译版本时,可以修改 module 依赖

dependencies {
    // ...
    debugImplementation project(':basecomponents')
    releaseImplementation project(':basecomponents')
}

修改资源路径时请慎重,因为非常容易出问题,而且很难搞~


4. 给 module 添加资源前缀 resourcePrefix

app 不管有多少 module ,最后都是整合到一起打成一个 dex 的,除非 dex 太大,报 65535了,才会拆分多个 dex 。所以 module 中的资源文件都会何必在一起的,这样难免会出现资源重名的问题,这可是会报错的,怎么办?

google 提供了 resourcePrefix 资源前缀

andorid{
    ...

    buildTypes{
        ...
    }

    resourcePrefix "moudle_prefix"
}

但是这样也不是就高枕无忧了,resourcePrefix 可以给 res 文件夹下的文件加前缀,但是图片资源就不行了,图片我们还是需要在命名时自己添加前缀


5. 去除重复依赖

这里我们要解决的是,我们引入的远程依赖中依赖的组件和我们本地远程依赖存在版本号的差异,这样 as 在编译的时候很多时候报错

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile("com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion") {
        exlude module: 'support-v4'//根据组件名排除
        exlude group: 'android.support.v4'//根据包名排除
    }
}

5.1 arr 打包不打 jar 进来

在打包 libs module realese版本 的 arr 时,是包含libs目录下的文件,这时候你引入这个aar,可能会和你现有引入的jar文件冲突,着要求我们在打包 aar 的时候设置不引入libs文件,做法是使用 compile 依赖本地 jar 文件

dependencies {

// 去掉默认 libs 文件夹依赖
// implementation fileTree(include: ['*.jar'], dir: 'libs')

// 转而使用 compile files + jar 的方式提供依赖
compile files('libs/commons-lang-2.6.jar')
compile files('libs/simple-xml-2.7.jar')
compile files('libs/agnes_tracker-0.1.0.jar')
}

6. 修改 module 路径

我们在开发时总是愿意把相同类型的类放在一起,这点放到 module 身上也是一样的,比哦如我希望业务组件类型的 module 都在一个文件夹下,这样好看好找不是

module 的配置是在 根项目 的 setting.gradle 中,那么我们去 setting.gradle 里面改好了

通常的 module 路径配置我们这么写

include ':app', ':basecomponents', ':baselib', ':common_repositroy'

但是我们可以自己在 根项目 里新建一个文件夹,然后把 module 放进去,那么我们这样写就行

project(':basecomponents').projectDir = new File( 'components/basecomponents' )
project(':common_repositroy').projectDir = new File( 'components/common_repositroy' )

7. gradle 修改 manifest 配置文件参数

在 manifest 配置文件我们可以定义 <meta-data> 参数,这个 <meta-data> 参数在 gradle 文件中可以修改的,这也是多渠道打包的基础

<meta-data>

  <meta-data
            android:name="UMENG_CHANNEL"
            android:value="${UMENG_CHANNEL_VALUE}"/>

gradle 修改值

manifestPlaceholders = [UMENG_CHANNEL_VALUE: "yingyongbao"]

大家在集成友盟统计时,就是这么干的


8. gradle 中创建参数

我们在 gradle 声明一个参数,然后根据不同的环境,修改为不同数据,这个最典型的应用就是 baseUrl 的处理了,debug 和 release 环境下 baseUrl 是不同的

gradle 声明参数有2种写法:

// 注意字符串单引号里面要套双引号
buildConfigField 'String', 'app_name', '"HHHHHH"'

// 在 values 中声明参数
resValue "color", "flav_color", "#00ffff"

java 代码获取参数

Log.d("test", BuildConfig.app_name);

tx_info.setTextColor(getResources().getColor(R.color.flav_color));

这里我们来看看 debug 和 release 环境下修改 baseUrl

    buildTypes {

        debug{
            buildConfigField( 'String','baseUrl','"baseUrl_debug"' )
        }
        release {
            buildConfigField( 'String','baseUrl','"baseUrl_release"' )
        }
    }
        btn_toast.setOnClickListener({
            ToastComponent.instance.show("baseUrl = " + BuildConfig.baseUrl);
        })

经过测试的确是可以改变 baseUrl 参数的


9. NDK 配置

1. 配置 SO 支持库类型
android {

    defaultConfig {
        ndk {

            // APP的build.gradle设置支持的SO库架构
            abiFilters 'armeabi', 'armeabi-v7a', 'x86'
        }
    }
}

这个 so 库配置声明了我们支持哪些 CPU 架构,一般现在我们除了 ARM CPU 架构外都不考虑了,这个配置我们写在 module 公共配置项 common.gradle 里面

2. 配置 SO 支持库位置

android{   
   sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
}

这样我们就可以把 .jar 和 .so 放在一起了


10. buildType 不同编译类型种我们一般都配置什么

基本上都是配 混淆,签名,各种参数,AndroidManifest 的 mate_data,其他的看字个特殊需求了

// 签名配置
signingConfigs {
    debug {
        storeFile file("../debug.jks")
        storePassword "123456"
        keyAlias "debug"
        keyPassword "123456"
    }
    release {
        storeFile file("../release.jks")
        storePassword "123456"
        keyAlias "release"
        keyPassword "123456"
    }
}

// 编译类型中我们通畅的配置项
buildTypes {
    debug {

        // 混淆配置
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        // 签名配置
        signingConfig signingConfigs.debu

        // 各种参数配置,比如 URL
        buildConfigField "String", "URL_HOST","\"https://XXXX.XXXX.XXXX/""
        buildConfigField "String", "QQ_APPID", "\"11111111111\""
        buildConfigField "String", "QQ_APPSECRET", "\"XXXXXXXXXXXXXXXX\""
        buildConfigField "Boolean", "DEBUG_TAG", "true"

        // AndroidManifest 的各种 mate_data
        manifestPlaceholders = [BAIDU_KEY_VAULE        : "fffffffffffffffffffff"]
        manifestPlaceholders = [UMENG_CHANNEL_VALUE    : "xxxxxxxxx"]
    }

    release {

        minifyEnabled true //开启混淆编译
        shrinkResources true //移除无用资源
        zipAlignEnabled true //zipalign优化
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        signingConfig signingConfigs.release

        buildConfigField "String", "URL_HOST","\"https://XXXX.XXXX.XXXX/""
        buildConfigField "String", "QQ_APPID", "\"11111111111\""
        buildConfigField "String", "QQ_APPSECRET", "\"XXXXXXXXXXXXXXXX\""
        buildConfigField "Boolean", "DEBUG_TAG", "false"

        manifestPlaceholders = [BAIDU_KEY_VAULE        : "fffffffffffffffffffff"]
        manifestPlaceholders = [UMENG_CHANNEL_VALUE    : "xxxxxxxxx"]
    }
}

11. 自定义 apk 名字

android {
    // 自定义输出apk名字
    applicationVariants.all {
        variant ->
            variant.outputs.all { output ->
                outputFileName = new File("app_" +
                        buildType.name +
                        "_v" + defaultConfig.versionName + "_" +
                        new Date().format("yyyy-MM-dd")+ ".apk")
            }
    }
}

跟着上面写就行,grooy 语言兼容 java 语法,上面的写法基本算是固定的



12. 多渠道打包

多渠道打包 gradle 代码不难,和 buildType 一个思路,根据不同的渠道改相应的参数或是资源

比如友盟统计:

/*配置渠道*/
productFlavors {
    wandoujia{
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
    }
    yingyongbao{
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "yingyongbao"]
    }
   huawei{
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: "huawei"]
    }
  ........
}

    //自动替换清单文件中的渠道号
    productFlavors.all {
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
    }

这样打渠道包的缺点:

  • 每一个渠道包需要release一次
  • 我们上传应用市场的时候都需要加固,加固后渠道信息会丢失,所以必须加固后再打渠道包

使用360加固时,支持多渠道打包,这样使用比较方便


注意:友盟统计的渠道号不能全是数字

还有一种是使用三方开源的打包工具,比如美团开源的打包工具:walle


13. 自动维护版本发布文档 gradle 脚本

这个脚本,我是看这篇文章找到的,很赞

gradle 脚本:releaseinfo.gradle

import groovy.xml.MarkupBuilder

/**
 * 描述:版本发布文档自动维护脚本
 * 流程描述:
 *           1、将版本相关信息解析出来
 *           2、将解析出的数据生成xml格式数据
 *           3、写入到已有的文档数据中
 **/
ext {
    versionName = rootProject.ext.android.versionName
    versionCode = rootProject.ext.android.versionCode
    versionInfo = 'App的第1个版本,上线了一些最基础核心的功能,主要是要通过审核'
    destFile = file('releasesInfo.xml')//指定输出文件
    if (destFile != null && !destFile.exists()) {
        destFile.createNewFile()
    }
}
//挂在到应用构建的过程中
this.project.afterEvaluate { project ->
    def buildTask = project.tasks.getByName('assembleRelease')
    if (buildTask != null) {
        buildTask.doLast {//assembleRelease 之后执行
            releaseInfoTask.execute()
        }
    }
}
//创建一个Task,并指定输入输出
task releaseInfoTask {
    inputs.property('versionCode', this.versionCode)
    inputs.property('versionName', this.versionName)
    inputs.property('versionInfo', this.versionInfo)
    outputs.file this.destFile
    doLast {
        //将输入的内容写入到输出文件中去
        def data = inputs.getProperties()
        File file = outputs.getFiles().getSingleFile()
        def versionMsg = new VersionMsg(data)
        //将实体对象写入到xml文件中
        def sw = new StringWriter()
        def xmlBuilder = new MarkupBuilder(sw)
        if (file.text != null && file.text.size() <= 0) {
            //没有内容
            xmlBuilder.releases {
                release {
                    versionCode(versionMsg.versionCode)
                    versionName(versionMsg.versionName)
                    versionInfo(versionMsg.versionInfo)
                }
            }
            //直接写入
            file.withWriter { writer ->
                writer.append("<?xml version=\"1.0\" encoding=\"GBK\"?>" + '\r\n')
                writer.append(sw.toString())
            }
        } else {//有内容判断版本是否改变
            def releases = new XmlParser().parse(file)
            def codeName = releases.release[-1].versionName.text()
            if (codeName != versionMsg.versionName) {//新的版本信息
                xmlBuilder.release {
                    versionCode(versionMsg.versionCode)
                    versionName(versionMsg.versionName)
                    versionInfo(versionMsg.versionInfo)
                }
                //插入到最后一行前面
                def lines = file.readLines()
                def lengths = lines.size() - 1
                file.withWriter { writer ->
                    lines.eachWithIndex { line, index ->
                        if (index != lengths) {
                            writer.append(line + '\r\n')
                        } else if (index == lengths) {
                            writer.append('\r\n' + sw.toString() + '\r\n')
                            writer.append(lines.get(lengths))
                        }
                    }
                }
            }
        }
    }
}
//信息实体类
class VersionMsg {
    String versionCode
    String versionName
    String versionInfo
}

app module 壳工程依赖这个脚本就行啦

apply from: rootProject.file('releaseinfo.gradle')

然后我们在打 release 包之后就在 app 项目下自动生成 releaseInfo.xml文件


<?xml version="1.0" encoding="GBK"?>
<releases>
  <release>
    <versionCode>1</versionCode>
    <versionName>1.0</versionName>
    <versionInfo>App的第1个版本,上线了一些最基础核心的功能,。。。。。。</versionInfo>
  </release>
</releases>

14. gradle 标准组件化设置

组件化中要求我们的 业务module 可以在 library 和 application 中任意切换,测试时我们可以把 业务module 单独打成一个 apk 去运行,插件化时我们也是把 业务module 打成 apk 下发到壳工程 APP

  1. 工程根目录下的 gradle.properties 中配置业务组件 Library/Application 切换的开关
isRunLogin = false  //login组件
isRunHome = false //home组件
isRunNews = false  //news组件

// 切换 application/Library 
if (isRunHome.toBoolean()){
    apply plugin: 'com.android.application'
}else{
    apply plugin: 'com.android.library'
}
}

注意:其实每个 modul 里面自己也可以放一个 gradle.properties,在自己 module 的 build.gradle 中都可以读出来

  1. 不同 buildType 设置不同的资源,文件路径,包括使用不同包下的class 和忽略一些不需要的包
android {
    .......

sourceSets {
        main {
            if (isModule.toBoolean()) {
                // 组件化编译时为app,在对应的AndroidManifest文件中需要写ndroid.intent.action.MAIN入口Activity
                manifest.srcFile 'src/main/module/AndroidManifest.xml'
                // 多级 java 目录
                java.srcDirs 'src/main/module/debug', 'src/main/java'
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
                //集成开发模式下排除debug文件夹中的所有Java文件
                java {
                    // 可以排除文件夹 - debug文件夹中放的是Application类,非组件化时不用有此类
                    exclude 'debug/**'
                    // 也可以重新指定文件夹 - 只保留原有的java目录
                    java.srcDirs 'src/main/java'
                }
            }
        }
    }
  1. 业务 module 单独打成 apk 时,我们要设置进程 ID 的,并且主工程此时是不能依赖编译模式是 application 的子 module 的



代码隔离

主要针对 app 壳工程来说的,壳工程会依赖所有的 module,但是在组件化中我们一样会要求 app 这个 module 不能直接使用其他业务 module 的 api,虽说我们可以用代码规范来严格要求,但是保不住哪里我们自己没注意就用了呢,所以就需要代码隔离了,在编码时不依赖,编译时依赖,这里我们就需要借助 runtimeOnly 了



多渠道动态配置 ApplicationId,App名字,AppLogo

这是别人的方案:https://www.jianshu.com/p/f3b3e947ae04

核心思路是在 java/main 之外创建和 main 同级别的目录存放资源,然后在配置文件里使用动态参数,在 gradle 的多渠道中赋值


1

2
3

参考资料:


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,706评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,002评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,462评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,375评论 0 216
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,763评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,849评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,033评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,768评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,490评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,734评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,204评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,566评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,227评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,137评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,934评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,926评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,774评论 2 274

推荐阅读更多精彩内容