gradle知识汇总

本人用Android studio也已经一年多了,现在回过头来写写gradle相关的知识点,希望能给新手带来些许帮助,大神勿喷

1、gradle的基本配置

每次新建一个module,在build.gradle文件中,都会自动生成如下配置:


gradle知识汇总_第1张图片

我们知道,在eclipse开发中,应用程序包名是由manifest下的package属性决定的:


然而在使用gradle构建的项目中,却多了一个applicationId属性,并且应用程序包名是由这个applicationId决定的:

defaultConfig {
    applicationId "com.xxx.xxxx"
}

通常gradle中的 applicationId 和Manifest中的 package 是一样的,当然也可以不一样,官方对两者的界定给出的解释是:
applicationId是应用在商店的唯一标识;
package是引用资源的路径名,也就是R文件的包名.

2、gradle的签名配置

关于签名的概念不懂得,可以参考这篇blog:Android从零单排之签名打包

签名配置的语法在项目的【Project Structure】中可以找到:

gradle知识汇总_第2张图片

如上图所示补全签名信息就可以在build.gradle中自动生成签名配置.

当然,更一般的配置方法是在build.gradle中手动书写签名配置:

android {
    signingConfigs {
        config_release {
            keyAlias 'releaseKey'
            keyPassword '123456'
            storePassword '123456'
            storeFile file('key/releaseKey.jks')
        }

        config_debug {
            keyAlias 'debugKey'
            keyPassword '123456'
            storePassword '123456'
            storeFile file('key/debugKey.jks')
        }
    }
    ......//省略其他配置
}

这里配置了两个签名,签名文件都放在app下面的key文件夹中,所以使用的是相对路径.

gradle知识汇总_第3张图片

如果将签名密码直接写在gradle中显然并不是很安全的做法,我们最好还是做点保密措施:在gradle中隐藏Keystore密码

3、 配置buildTypes

语法在项目的【Project Structure】中也能找到:

gradle知识汇总_第4张图片

这里可配置的信息很多,一般是在buildTypes{ }里面配置两个(release和debug):

buildTypes {
    release {
        signingConfig signingConfigs.config_release
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug {
        signingConfig signingConfigs.config_debug
    }
}

4、 配置productFlavor

多渠道打包,关键就在于productFlavor:

productFlavors {
    flavor_1 {
        minSdkVersion 14
        signingConfig signingConfigs.config_release
        targetSdkVersion 23
        versionCode 2
        versionName '2.0.1'
        applicationId 'com.huaihuai.android.one'
    }
    flavor_2 {
        minSdkVersion 10
        signingConfig signingConfigs.config_debug
        versionCode 1
        versionName '1.0.0'
        applicationId 'com.huaihuai.android.two'
    }
}

我们这里给不同渠道配置不同的applicationId,就可以打包出多个不同渠道不同包名的apk.

这样有一个应用场景就是:包名不同的apk可以共存在一个手机上,利用这点我们可以在测试机上运行多个版本的apk以方便测试.

productFlavors{ } 与 buildTypes{ }里面的配置是多对多的关系.
比如:

android {
    buildTypes {
        release {...}
        debug {...}
    }
    productFlavors {
        flavor_1 {...}
        flavor_2 {...}
    }
}

这时的配置可以打出4个apk,分别是:

#5、打包命令

强烈推荐使用gradlew命令行进行打包,因为gradle下很多方便的配置只有以命令行的方式才能正常打包,后面会讲到.

比如我们打包flavor_1渠道下对应的release和debug版本:

gradle知识汇总_第5张图片

当然,我们也不用去背这些gradle命令,因为在Android studio的右侧会有【Gradle】tab页面,里面包含了我们常用的命令:

gradle知识汇总_第6张图片

6、manifest占位符

在打包多个版本的时候,会遇到修改应用名称等需求。不同的flavor有要求不同的名称. 此时可以在Manifest文件中使用占位符,然后在build.gradle中替换占位符就行了.

首先定义占位符:


    
        
            

            
        
    

在build.gradle中替换:

buildTypes {
    release {
        signingConfig signingConfigs.config_release
        minifyEnabled false
        manifestPlaceholders = [APP_NAME: "@string/app_name1"]
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug {
        signingConfig signingConfigs.config_debug
        manifestPlaceholders = [APP_NAME: "@string/app_name2"]
    }
}

productFlavors {
    flavor_1 {
        minSdkVersion 14
        signingConfig signingConfigs.config_release
        targetSdkVersion 23
        versionCode 2
        versionName '2.0.1'
        applicationId 'com.huaihuai.android.1'
        manifestPlaceholders = [APP_NAME: "@string/app_name1"]
    }
    flavor_2 {
        minSdkVersion 10
        signingConfig signingConfigs.config_debug
        versionCode 1
        versionName '1.0.0'
        applicationId 'com.huaihuai.android.2'
        manifestPlaceholders = [APP_NAME: "@string/app_name2"]
    }
}

如上,如果在productFlavors和buildTypes里面都进行了替换,那么是以productFlavors里面的为准.

如果不区分productFlavors和buildTypes的话,只是单纯修改应用名称的话,也可以在defaultConfig里进行替换:

defaultConfig {
    applicationId "com.huaihuai.android"
    minSdkVersion 14
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"
    manifestPlaceholders = [APP_NAME: "@string/app_name"]
}

其实defaultConfig也是productFlavors的一个子集.

7、添加自定义字段

我们有时候需要运行的时候有不同的表现.
比如,release版本不显示log信息,debug版本显示log信息

这时候我们可以通过buildConfigField、resValue在gradle里面自定义一些字段:

buildConfigField "boolean", "showLog", '"false"'
resValue "String", "build_time", '"11110000"'

添加完毕之后,就可以在代码中使用了:

System.out.println(BuildConfig. showLog);
System.out.println(getString(R.string.build_time))

注意两者使用方法并不相同,resValue定义的字段更像是资源文件*.xml下定义的字段,此外它们还有以下区别:
1、buildConfigField可定义字段为基本数据类型
2、buildConfigField定义的字段会显示在BuildConfig类中
3、resValue可定义字段有:string(待补充)
4、resValue定义的字段会显示在generated.xml中

8、动态设置一些额外信息

假如想把当前的编译时间、编译的机器、最新的commit版本添加到apk,而这些信息又不好写在代码里,强大的gradle给了我创造可能的自信:

android {
    defaultConfig {
        resValue "string", "build_time", buildTime()
        resValue "string", "build_host", hostName()
        resValue "string", "build_revision", revision()
    }
}

def buildTime() {
    return new Date().format("yyyy-MM-dd HH:mm:ss")
}

def hostName() {
    return System.getProperty("user.name") + "@" + InetAddress.localHost.hostName
}

def revision() {
    def code = new ByteArrayOutputStream()
    exec {
        commandLine 'git', 'rev-parse', '--short', 'HEAD'
        standardOutput = code
    }
    return code.toString()
}

这个地方,如何从命令行读取返回结果,很有意思.

9、给自己留个”后门”: 点七下

为了调试方便,我们往往会在debug版本留一个显示我们想看的界面(记得之前微博的一个iOS版本就泄露了一个调试界面),如何进入到一个界面,我们可以仿照android开发者选项的方式,点七下才显示,我们来实现一个:

private int clickCount = 0;
private long clickTime = 0;

sevenClickView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (clickTime == 0) {
            clickTime = System.currentTimeMillis();
        }
        if (System.currentTimeMillis() - clickTime > 500) {
            clickCount = 0;
        } else {
            clickCount++;
        }
        clickTime = System.currentTimeMillis();
        if (clickCount > 6) {
            // 点七下条件达到,跳到debug界面
        }
    }
});

release版本肯定是不能暴露这个界面的,也不能让人用am在命令行调起,如何防止呢,可以在release版本把这个debug界面的exported设为false.

10、自定义导出APK的名称

两种方式实现:

/*applicationVariants.all {
            variant ->
                variant.outputs.each {
                    output ->
                        def outputFile = output.outputFile
                        if (outputFile != null && outputFile.name.endsWith('.apk')) {
                            def apkType = ""
                            if (variant.flavorName.equals("flavor_1")) {
                                apkType = "flavor_1"
                            } else if (variant.flavorName.equals("flavor_2")) {
                                apkType = "flavor_2"
                            }
                            def fileName = new File(output.outputFile.getParent(),
                                    "app-" + apkType + "-${variant.versionName}.apk")
                            output.outputFile = fileName
                        }
                }
        }*/
applicationVariants.all {
    variant ->
        variant.outputs.each {
            output ->
                def outputFile = output.outputFile
                if (outputFile != null && outputFile.name.endsWith('.apk')) {
                    def fileName = outputFile.name.replace(".apk",
                                    "-${defaultConfig.versionCode}-${defaultConfig.versionName}.apk")
                    output.outputFile = new File(outputFile.parent, fileName)
                }
         }
}

这里就不多讲了,大家运行测试一下就明白了.

至此,文章结束,希望此文能帮助到你,如果对此文有不同见解,欢迎直接评论!

参考文案:
Gradle的神奇之处
Android项目中如何用好构建神器Gradle?
Android 使用Android Studio + Gradle 或 命令行 进行apk签名打包

你可能感兴趣的:(gradle知识汇总)