文档章节

Gradle打包APK的一些小技巧和productFlavor配置

SuShine
 SuShine
发布于 2016/08/01 22:41
字数 1552
阅读 2.7K
收藏 3

「深度学习福利」大神带你进阶工程师,立即查看>>>

前言

在使用Gradle来打包Android应用之前,Android自动化打包通常会选择使用ant,ant是一种一步一步来执行任务的工具,通常打包一个apk要经过一个复杂的过程,ant工具通过一步一步完成这些过程来生成一个apk。如果要实现一个复杂一点的打包过程,它的xml配置文件的长度也是足以让你崩溃的。Gradle的出现让打包过程变得十分轻松,而且配置起来也是简单易懂。以前需要写好几天的配置文件现在只要简单的几步就能完成,配合Android Studio更加得心应手。

一个完整的打包流程如下: pic

基本的build.gradle

如果你用Android Studio生成一个项目的话,在app模块中你会看到一个build.gradle文件,这个文件就是配置这个模块的地方,大致文件结构如下:

    
apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:19.0.1'
}

这里就不一行行地解释了,关于Gradle的语法可以自行Google。

这里主要有两个小技巧

  1. 签名:开发App时经常遇到Release版和Debug版共存问题,由于默认的签名不同,经常要卸载Debug版安装Release版,非常麻烦。有两种方法可以避免这种情况:1. 使用同一个签名;2. 使用不同包名
// 方法1 (签名配置方法可以Google)
android {
   buildTypes {
       debug {signingConfig signingConfigs.myConfig}
       release {signingConfig signingConfigs.myConfig}
   }
}
// 方法2 
android {
   buildTypes {
       debug {packageNameSuffix ".debug"}
   }
}
  1. Release版打包的apk文件名:通过下面的代码可以自动为生成的apk文件附加上版本和build日期,这里可以根据你的需求添加各种信息上去。
android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

            def today = new Date()
            if (variant.buildType.getName().equals("release")) {
                println "Change output apk name"
                variant.outputs.each { output ->
                    output.outputFile = new File(
                            output.outputFile.parent,
                            output.outputFile.name.replace(".apk", "-" + defaultConfig.versionName + "-" + today.format('yyyyMMdd') + ".apk"))
                }
            }
        }
    }
}

BuildVariants

Gradle的Android插件中有个BuildVariants的概念,其实简单来说其实就是buildTypes+productFlavors,buildType前面我们看到过了,主要就是debug和release的分别。而productFlavors就是我们用来打包不同版本app的主要方式。从字面意思来翻译指的就是不同的“产品特点”。

Android Studio会自动根据build.gradle 生成对应的BuildVariants。比如以下代码:

android {
    productFlavors {
        free {}
        paid {}
    }
}

会生成以下的BuildVariants:

pic

productFlavors的维度

productFlavors可以是多维的,听起来好像很难理解,这里举个栗子,有如下代码:

android {
    flavorDimensions("isfree", "channel")
    productFlavors {
        free {dimension "isfree"}
        paid {dimension "isfree"}

        googleplay {dimension "channel"}
        wandoujia {dimension "channel"}
    }
}

能够生成如下的BuildVariants:

pic

这里我们就可以看到,我们有两个维度,一个是是否免费,另一个是渠道,我们能够生成2*2=4种Flavor,并且每个Flavor都有debug和release,总共就有8种不同的APK。所以理论上来说通过组合Flavor,我们可以做到各种不同的分类。

接下来我们来看看productFlavors能做什么? ### 定义渠道

在国外一般来说开发者不太需要去管渠道的问题,他们的App只需要发往GooglePlay就可以了,但是在中国,我们有众多的APK分发平台,我们的APK需要发往各种地方,在做APP统计的时候我们就需要在APK里写入一些特征变量,发送到统计平台,以区分不同的渠道,在过去用ant打包的时代,我们通常的做法就是用不同的渠道名来重复ant任务一遍一遍地打包。

如果用gradle:我们可以通过增加一个名为channel的dimension来给每一个渠道一个特殊标示,代码就是我们之前看到的。但是你可能会问,我怎么在统计的时候获取这个渠道名呢?其实很简单,Android Studio会为我们生成一个名叫BuildConfig的类,这个类有一些关于打包的静态变量,下面是一个示例:

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "me.zheteng.android.example";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "freeGoogleplay";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
  public static final String FLAVOR_isfree = "free";
  public static final String FLAVOR_channel = "googleplay";
}

其实不止是渠道,通过这个类我们还可以很方便地获得这个APK的各种信息。相信大家一眼就能看出来每个字段的意思。(我们甚至还可以自定义字段)。

如果渠道非常多,你也可以通过读配置文件的方式动态生成不同的flavors。

如果我每个flavor都有点特别呢?

有的时候我们每个flavor可能不只是一个渠道名这么简单,我的ICON可能给每个渠道的有所不同,我的包名也可能有所不同。所有这些,都可以直接在这个flavor中重新定义:

android {
    productFlavors {
        googleplay {
            applicationId "me.zheteng.android.example.googleplay"
        }
    }
}

如果需要不同的源代码或资源文件,可以在app/src下新建一个名为“flavor名”的目录(这里就是googleplay)。也就是app/src/googleplay,然后这个目录下的结构和app/src/main中是一样的,打包的时候会优先使用当前flavor下的文件。

其他Gradle小技巧

Provider名称

我们知道Provider的authority是系统中全局唯一的,有时候我们要为不同的flavor将authority改成不同的,通过gradle你可以这样实现:

<provider
    android:exported="true"
    android:name="com.path.to.my.Provider"
    android:authorities="${applicationId}.provider"/>

你问我Java代码中怎么获取?难道你忘了BuildConfig了嘛?

Manifest 占位符

有些SDK会把配置在Manifest文件中的meta信息里,而不同的flavor这个信息不一样,这是我们可以通过Manifest 占位符来实现:

<meta-data android:value="${UMENG_APPKEY}" android:name="UMENG_APPKEY"/>
android {
    productFlavors {
        googleplay {
            applicationId "me.zheteng.android.example.googleplay"
            manifestPlaceholders = [UMENG_APPKEY: "我的友盟KEY"]
        }
    }
}

总结

Gradle的灵活程度超乎想象,如果基本功能无法满足你,你还可以通过自己编写Groovy插件或者task来实现无穷的可能性,欢迎将你的思路分享出来~

SuShine
粉丝 131
博文 633
码字总数 160326
作品 0
朝阳
后端工程师
私信 提问
加载中
请先登录后再评论。
记一次失败的Perl + Nginx + FastCGI 配置过程

这两天心血来潮,不知道为什么和 Perl + Nginx + FastCGI 配置 耗上了。但是失败了,记录如下: 1)安装Nginx 1.4.3 ,我的是WINDOWS 7 系统,修改配置文件如下: location ~ .(pl|cgi|perl)?...

通吃岛-低手哥
2013/10/27
1.8K
7
Flappy Bird(安卓版)逆向分析(一)

更改每过一关的增长分数 反编译的步骤就不介绍了,我们直接来看反编译得到的文件夹 方法1:在smali目录下,我们看到org/andengine/,可以知晓游戏是由andengine引擎开发的。打开/res/raw/at...

enimey
2014/03/04
6.2K
18
SQLServer实现split分割字符串到列

网上已有人实现sqlserver的split函数可将字符串分割成行,但是我们习惯了split返回数组或者列表,因此这里对其做一些改动,最终实现也许不尽如意,但是也能解决一些问题。 先贴上某大牛写的s...

cwalet
2014/05/21
9.7K
0
CDH5: 使用parcels配置lzo

一、Parcel 部署步骤 1 下载: 首先需要下载 Parcel。下载完成后,Parcel 将驻留在 Cloudera Manager 主机的本地目录中。 2 分配: Parcel 下载后,将分配到群集中的所有主机上并解压缩。 3 激...

cloud-coder
2014/07/01
6.9K
1
程序猿媛一:Android滑动翻页+区域点击事件

滑动翻页+区域点击事件 ViewPager+GrideView 声明:博文为原创,文章内容为,效果展示,思路阐述,及代码片段。文尾附注源码获取途径。 转载请保留原文出处“http://my.oschina.net/gluoyer...

花佟林雨月
2013/11/09
4.3K
1

没有更多内容

加载失败,请刷新页面

加载更多

Subversion存储库中“分支”,“标记”和“主干”的含义是什么?

问题: I've seen these words a lot around Subversion (and I guess general repository) discussions. 我已经在Subversion(我猜通用存储库)讨论中看到了很多这样的话。 I have been us......

富含淀粉
今天
5
0
《Java8实战》笔记(03):Lambda表达式

本文源码 Lambda 管中窥豹 可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。 Lambda表达...

巨輪
今天
7
0
从其他文件夹导入文件 - Importing files from different folder

问题: I have the following folder structure. 我有以下文件夹结构。 application/app/folder/file.py and I want to import some functions from file.py in another Python file which r......

javail
今天
22
0
大数据研发学习之路--Hadoop集群搭建

阅读编译文档 准备一个hadoop源码包,我选择的hadoop版本是:hadoop-2.7.7-src.tar.gz,在hadoop-2.7.7的源码 包的根目录下有一个文档叫做BUILDING.txt,这其中说明了编译hadoop所需要的一些...

DSJ-shitou
今天
8
0
OSChina 周五乱弹 —— 特么是别的公司派来的特洛伊木马吧?

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 小小编辑推荐:《我会守在这里》- 毛不易 《我会守在这里》- 毛不易 手机党少年们想听歌,请使劲儿戳(这里) @FalconChen :股市连跪了五天,...

小小编辑
今天
77
2

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部