转载请注明出处:http://blog.csdn.net/crazy1235/article/details/50465885

Google I/O 2013大会上公布了AS,现在已经发展到2.0-beta版本号。相信已经大部分人做Android开发的都已经由Eclipse IDE转为AS IDE。

随着AS版本号的更迭,也带来不少为为开发人员提供便利的工具。比方这篇blog所描写叙述的:http://blog.csdn.net/crazy1235/article/details/49747141

本人从AS1.2版本号開始使用,现在也用了大半年了。现将使用过程中的一些经验分享给大家。


gradle的基本配置

apply plugin: 'com.android.application'

android {
compileSdkVersion 23
buildToolsVersion "23.0.2" defaultConfig {
applicationId "com.jacksen.multichannel"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
} dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:design:23.1.1'
}

上面的就是一个项目gradle的基本配置。

apply plugin: 'com.android.application'

表示该module是一个app module。应用了com.android.application插件,也就是主程序。

假设是一个第三方library,则应该是app plugin: ‘com.android.library’

buildTypes { } 表示构建类型。包含release和debug两种。

能够在这里面配置启用混淆、zipAlign、签名信息等。

dependencies { } 里面是项目的依赖信息,包含jar包和第三方库等信息。

ApplicationId与PackageName的差别:

此前使用eclipse进行开发的时候,应用程序的包名是由manifest文件的package属性决定的:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxx.xxxx"
android:versionCode="1"
android:versionName="1.0" >

然而在使用gradle构建的时候却多了一个applicationId。通常gradle中的applicationId和Manifest中的package是一样的。事实上能够使二者一致。

官方解释说是:applicationId是你的应用在商店的唯一标识。

而package是引用资源的路径名,也就是R文件的包名。

上面我们说到二者能够不一致,我们能够通过对不同的Flavor设置不同的applicationId,从而能够导出不同“包名”的apk。而不须要改动其它的代码。后面会细致说明。


gradle的签名配置

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

我们通常执行项目都是使用debug的签名。只是有些使用到第三方sdk的时候,须要用到正式版的签名,通过打包正式签名的方式又不好调试。只是我们能够在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')
}
}
......//省略其它配置
}

这里配置了两个签名。jsk都放在app以下的key目录中。所以使用的是相对路径。

之前有人问我是怎么知道keyAlias 、keyPassword这些语法的。

事实上在项目的【Project Structure】中都能够找到。


配置buildTypes

一般在buildTypes{ }里面配置两个(release和debug):

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
shrinkResources true //移除无效的resource文件,必须同意ProGuard才干生效
zipAlignEnabled true
buildConfigField "boolean", "APP_TYPE", "true"
manifestPlaceholders = [APP_NAME: "@string/app_name_release"]
signingConfig signingConfigs.config
}
debug {
buildConfigField "boolean", "APP_TYPE", "false"
// manifestPlaceholders = [APP_NAME: "@string/app_name_debug"]
applicationIdSuffix 'debug'
}
}

这里可配置的信息非常多,比方:能否够是debug模式、签名配置、混淆文件等。


配置productFlavor

多渠道打包。关键就在于定义多个productFlavor。

在一个flavor里面可配置的信息非常多。

productFlavors {
flavor_release {
buildConfigField "boolean", "APP_TYPE", "false"
applicationId 'com.jacksen.multichannel.release'
signingConfig signingConfigs.config_release
minSdkVersion 9
targetSdkVersion 15
versionCode 2
versionName '2.0.1'
}
flavor_debug {
minSdkVersion 10
applicationId 'com.jacksen.multichannel.debug'
signingConfig signingConfigs.config_debug
versionCode 5
versionName '5.0'
}
}

最基本的是能够在这里配置applicationId,就是我们上面一開始说的打包多个不同“包名”的apk。

这样有一个应用场景就是,我们一般通过debug版本号进行測试之后,在进行release版本号的測试。

只是同一个applicationId的apk在一个測试机上仅仅能存在一个。现在我们通过配置多个flavor相应多个applicationId。就能够在測试机上执行測试版和正式版两个apk了


productFlavors{ } 与 buildTypes{ }里面的配置是多对多的关系。

比方:

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

此时的配置能够打包出四个apk,各自是:

我们在使用as的打包工具时,能够选择打包某一个Build type的某一个或多个Flavors:

假设在gradle里面配置了签名信息,那么在【Generate Signed APK】的第一步填写的签名信息是以在gradle里面配置并引用的为准。

我们还能够借助gradlew命令来打包:

比方打包flavor_1相应的release和debug版本号:

打包flavor_2相应的release版本号:

实际上。我们不用再记住这些命令。

AS里面的gradle插件就能够实现。

在AS的右側会有【Gradle】tab页面。打开之后。先刷新一下。

会看到例如以下图示:

通过双击右边的命令打包不同的版本号。

除了build以下的命令,还有其它的命令。大家都能够尝试一下。依据名字应该就能知道什么意思,这里不多介绍了。


manifest占位符

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

首先定义占位符:

application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="${APP_NAME}"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".LoginActivity"
android:label="${APP_NAME}">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

在build.gradle中替换:

buildTypes {
release {
manifestPlaceholders = [APP_NAME: "@string/app_name1"]
}
debug {
manifestPlaceholders = [APP_NAME: "@string/app_name1"]
}
}
 productFlavors {
flavor_1 {
manifestPlaceholders = [APP_NAME: "@string/app_name1"]
}
flavor_2 {
manifestPlaceholders = [APP_NAME: "@string/app_name2"]
}
}

假设在productFlavors和buildTypes里面都进行了替换,那么是以productFlavors里面的为准

假设不区分productFlavors和buildTypes的话,也能够在defaultConfig里进行替换:

defaultConfig {
manifestPlaceholders = [APP_NAME: "@string/app_name_release"]
}

事实上defaultConfig也是productFlavors的一个子集。


加入自己定义字段

Gradle在generateSources阶段为每个flavor生成两个BuildConfig.java文件(相应在release和debug目录下)。

BuildConfig类默认会提供一些常量字段。

public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.jacksen.multichannel";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
}

尽管通过上面的操作,我们能够同一时候打包出一个debug版本号和一个release版本号。

可是我们还须要执行的时候有不同的表现。比方。release版本号不显示一些控件。

令人惊奇的是,我们能够通过buildConfigField在gradle里面自己定义一些字段。

buildConfigField "String", "APP_TYPE", "debug"

我们能够查看buildConfigField的源代码:

/**
* Adds a new field to the generated BuildConfig class.
*
* <p>The field is generated as: <code>&lt;type&gt; &lt;name&gt; = &lt;value&gt;;</code>
*
* <p>This means each of these must have valid Java content. If the type is a String, then the
* value should include quotes.
*
* @param type the type of the field
* @param name the name of the field
* @param value the value of the field
*/
public void buildConfigField(
@NonNull String type,
@NonNull String name,
@NonNull String value) {
ClassField alreadyPresent = getBuildConfigFields().get(name);
if (alreadyPresent != null) {
logger.info(
"BuildType(${getName()}): buildConfigField '$name' value is being replaced: ${alreadyPresent.value} -> $value");
}
addBuildConfigField(AndroidBuilder.createClassField(type, name, value));
}

凝视写的非常具体。该方法就是加入一个field到BuildConfig类中。

三个參数都是不可为空的

加入完成之后,就能够在代码中使用了:

textView.setText("BuildConfig.APP_TYPE : " + BuildConfig.APP_TYPE);

自己定义导出APK的名称

我直接上代码吧。

/*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.versionName}.apk")
def apkType = ""
if (variant.flavorName.equals("releaseFlavor")){
apkType = "release"
}else if(variant.flavorName.equals("debugFlavor")){
apkType = "debug"
}
def fileName = new File(output.outputFile.getParent(), "app-" + apkType + "-${variant.versionName}.apk")
// output.outputFile = new File(outputFile.parent, fileName)
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的一些认识~~~


Demo下载

https://github.com/crazy1235/MultiChannel

欢迎star~~


參考:

http://tech.meituan.com/mt-apk-adaptation.html

http://www.jayfeng.com/2015/11/07/Android%E6%89%93%E5%8C%85%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B/

http://www.jcodecraeer.com/a/anzhuokaifa/Android_Studio/2015/0810/3281.html


此篇blog到此结束~

感谢大家支持!

如有错误,请指出~

谢谢~

Gradle的奇妙之处的更多相关文章

  1. [Gradle] 在 Eclipse 下利用 gradle 构建系统

      转载自:http://www.ibm.com/developerworks/cn/opensource/os-cn-gradle/ 构建系统时候常常要用到 Ant, Maven 等工具,对于初学者 ...

  2. Java序列化流的奇妙之旅

    Java序列化流有何奇妙之处呢?通过一个个案例逐一感受序列化流. !!!好戏在后头!!! 1.IO流读写文件 先从一个普通文件读写字符串开始讲起. 例子:输出字符串到文件,再从文件中读取字符串 在某一 ...

  3. Android 自己实现 NavigationView [Design Support Library(1)]

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/46405409: 本文出自:[张鸿洋的博客] 一.概述 Google I/O 2 ...

  4. 探寻 JavaScript 逻辑运算符(与、或)的真谛

    十二月已经过半,冬季是一个美妙的季节,寒冷的空气逼得人们不得不躲在安逸舒适的环境里生活.冬季会给人一种安静祥和的氛围,让人沉浸在其中,仿佛是一个旧的阶段的结束,同时也是一个新的阶段的开始.这么说来,西 ...

  5. linux内核分析作业8:理解进程调度时机跟踪分析进程调度与进程切换的过程

    1. 实验目的 选择一个系统调用(13号系统调用time除外),系统调用列表,使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 分析汇编代码调用系统调用的工作过程,特别是参数的传递的方 ...

  6. 一行python代码实现树结构

    树结构是一种抽象数据类型,在计算机科学领域有着非常广泛的应用.一颗树可以简单的表示为根, 左子树, 右子树. 而左子树和右子树又可以有自己的子树.这似乎是一种比较复杂的数据结构,那么真的能像我们在标题 ...

  7. Linux C 中 fork() 函数详解

    一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork() 函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同 ...

  8. [Linux]系统调用理解(2)

    本文介绍了Linux下的进程概念,并着重讲解了与Linux进程管理相关的4个重要系统调用getpid,fork,exit和_exit,辅助一些例程说明了它们的特点和使用方法. 关于进程的一些必要知识 ...

  9. dmidecode常用参数

    dmidecode常用参数详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. dmidecode这个命令真是神器啊,他能快速的获取服务器的硬件信息,而且这个命令有很多的花式玩法,今 ...

随机推荐

  1. CodeForces 131C C (组合)

    There are n boys and m girls attending a theatre club. To set a play "The Big Bang Theory" ...

  2. Spring配置之OpenSessionInViewFilter

    转自:https://www.cnblogs.com/blogonfly/articles/3991782.html 参考: OpenSessionInViewFilter作用及配置:http://w ...

  3. Java设计模式-策略模式详解

    前言 在软件领域中,设计模式作为一种经典的开发实践常常需要我们去深入的理解,而策略模式作为设计模式的一种,使用频率也是相对来说比较高的,在Java中,当我们学习TreeSet集合的时候,就采用了经典的 ...

  4. A - Boy or Girl(set)

    Problem description Those days, many boys use beautiful girls' photos as avatars in forums. So it is ...

  5. Tomcat 报错 记录

    Resource is out of sync with the file system: 该错误为替换了image中的图片而没有进行更新,造成找不到该资源,进而保存,解决只要eclipse刷新一下F ...

  6. JavaScript实现复选框的全选、不选、反选

    方法一: <html> <head> <meta charset="utf-8"> <title>无标题文档</title&g ...

  7. 了解jQuery的$符号

    $是什么? 可以使用typeof关键字来观察$的本质. console.log(type of $); //输出结果为function 因此可以得出结论,$其实就是一个函数.$(); 只是根据所给参数 ...

  8. ContentProvider 的使用

    1.简单示例:通过ContentProvider暴露数据库,然后读取数据. 2.先加上一个工具类,用来使用copy assets下面的db文件代码如下: public class MyDBOpenHe ...

  9. SQL触发器 inset自学经验

    本人建立了一个特价汇网站,想要记录每个商品的点击量和整个网站的访问量,于是就想用sql 触发器来实现 drop trigger tgr_cg_records_update_column create ...

  10. Windows上部署Python

    以Python 3.5为例 1.到https://www.python.org/downloads/windows/下载embeddable zip file类型的压缩包python-3.5.1-em ...