安卓开发完毕。对于一个开放应用而言,我们须要公布到不同的应用市场,同一时候我们也须要统计不同市场的用户下载量。

(通过启动应用后获取不同市场apk中的不同值来区分)

以下用一个详细的实例来说明:

1、在AndroidManifest.xml的application内加入meta-data标签

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"> <meta-data
android:name="APP_CHANNEL"
android:value="${APP_CHANNEL_VALUE}" /> <activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

2、改动build.gradle文件,在android {} 中加入

android {

    // 打包渠道List
productFlavors {
wandoujia {
manifestPlaceholders = [APP_CHANNEL_VALUE: "豌豆荚"]
}
cn360 {
manifestPlaceholders = [APP_CHANNEL_VALUE: "360"]
}
baidu {
manifestPlaceholders = [APP_CHANNEL_VALUE: "百度"]
}
tencent {
manifestPlaceholders = [APP_CHANNEL_VALUE: "应用宝"]
}
sougou {
manifestPlaceholders = [APP_CHANNEL_VALUE: "搜狗市场"]
}
} }

或者使用以下方法,直接使用flavor的name做为${APP_CHANNEL_VALUE}

android {

    // 打包渠道List
productFlavors {
wandoujia {}
cn360 {}
baidu {}
tencent {}
sougou {}
} // 批量处理,直接使用flavor的name作为APP_CHANNEL_VALUE的值
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [APP_CHANNEL_VALUE: name]
} }

这样就完毕了。运行 gradle assembleRelease 喝口茶坐等便可。

完毕后,到build/outputs/apk中就能够看到各种渠道包。

有关assemble可用的命令还有:

gradle assembleDebug    //全部Debug版本号
gradle assembleRelease //全部Release版本号
gradle assembleBaidu //指定渠道的Debug和Release版本号
gradle assembleBaiduDebug //指定渠道的Debug版本号
gradle assembleBaiduRelease //指定渠道的Release版本号
gradle build //全部渠道的Debug和Release版本号

最后附上我的 MainActivity 和 build.gradle

package com.example.myandroid;

import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.widget.Toast; /**
* 应用入口
*
* @author SHANHY(365384722@QQ.COM)
* @date 2015年12月30日
*/
public class MainActivity extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String channel = getAppMetaData("APP_CHANNEL");
if(channel != null)
Toast.makeText(this, channel, Toast.LENGTH_SHORT).show();
} /**
* 获取Application以下的metaData
*
* @param name
* @return
* @author SHANHY
* @date 2015年12月30日
*/
public String getAppMetaData(String meta_name){
try {
ApplicationInfo appInfo = this.getPackageManager()
.getApplicationInfo(getPackageName(),PackageManager.GET_META_DATA);
return appInfo.metaData.getString(meta_name);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
}

完整的 build.gradle 脚本

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0-alpha3'
}
} apply plugin: 'com.android.application' dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
} android {
compileSdkVersion 14
buildToolsVersion "23.0.2" defaultConfig {
// 能够手动改动例如以下一些配置。无需改动不论什么代码便能够生成相应配置的apk
applicationId "com.example.myandroid.aaa"
minSdkVersion 8
targetSdkVersion 21
versionCode 200
versionName "2.0.0" // dex突破65535限制
multiDexEnabled true
// 默认打包渠道(官方)
manifestPlaceholders = [APP_CHANNEL_VALUE: "官方"]
} // 打包渠道List
productFlavors {
myself {
manifestPlaceholders = [APP_CHANNEL_VALUE: "官方"]
}
wandoujia {
manifestPlaceholders = [APP_CHANNEL_VALUE: "豌豆荚"]
}
cn360 {
manifestPlaceholders = [APP_CHANNEL_VALUE: "360"]
}
baidu {
manifestPlaceholders = [APP_CHANNEL_VALUE: "百度"]
}
tencent {
manifestPlaceholders = [APP_CHANNEL_VALUE: "应用宝"]
}
sougou {
manifestPlaceholders = [APP_CHANNEL_VALUE: "搜狗市场"]
}
} // 打包渠道List
//productFlavors {
// myself {}
// wandoujia {}
// cn360 {}
// baidu {}
// tencent {}
// sougou {}
//} // 批量处理,直接使用flavor的name作为APP_CHANNEL_VALUE的值(也能够不使用该方法,在productFlavors中逐一配置)
//productFlavors.all { flavor ->
// flavor.manifestPlaceholders = [APP_CHANNEL_VALUE: name]
//} lintOptions {
abortOnError false
} sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
} // Move the tests to tests/java, tests/res, etc...
instrumentTest.setRoot('tests') // Move the build types to build-types/<type>
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
// This moves them out of them default location under src/<type>/... which would
// conflict with src/ being used by the main source set.
// Adding new build types or product flavors should be accompanied
// by a similar customization.
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
} //签名信息
signingConfigs {
debug{
// No Debug Config
} release {
storeFile file("xxxxx.key")
storePassword "xxxxx"
keyAlias "xxxxx"
keyPassword "xxxxx"
}
}
buildTypes {
//Debug模式
debug {
// 显示LOG,在java代码中的调用方式为:BuildConfig.LOG_DEBUG。AS工具能够在BuildConfig.java中新增这个字段,假设还要兼容使用eclipse,不建议使用新增字段,由于eclipse在clean后会又一次生成BuildConfig.java(默认使用BuildConfig.DEBUG能满足须要就不要特殊处理了)
//buildConfigField "boolean", "LOG_DEBUG", "true" versionNameSuffix "-debug"
// 不开启混淆
minifyEnabled false
// 不须要ZIP优化
zipAlignEnabled false
// 不须要资源压缩
shrinkResources false
// signingConfig
signingConfig signingConfigs.debug
} //Release模式
release {
// 不显示LOG
//buildConfigField "boolean", "LOG_DEBUG", "true" minifyEnabled true
zipAlignEnabled true
// 资源压缩,移除没用的资源文件
shrinkResources true
// 混淆文件配置
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// 签名信息配置(假设上面配置了defaultConfig则能够不用指定signingConfig)
signingConfig signingConfigs.release applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
// 输出apk名称为myandroid_v1.0.0_2015-12-30_baidu.apk
def fileName = "myandroid_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
}
}
} // 声明一个方法,获取打包时间
def releaseTime() {
return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}

Android 使用 Gradle 多渠道打包的更多相关文章

  1. Android Studio + gradle多渠道打包

    通过工具栏的Build->Build Apk 好像只能打包第一个Module(eclipse里面是Project的概念),怎么多渠道打包呢?目前好像只能一个一个的打 首先在清单文件里设置个变量: ...

  2. [转]Android Studio系列教程六--Gradle多渠道打包

    转自:http://www.stormzhang.com/devtools/2015/01/15/android-studio-tutorial6/ Android Studio系列教程六--Grad ...

  3. Android Studio系列教程六--Gradle多渠道打包

    Android Studio系列教程六--Gradle多渠道打包 2015 年 01 月 15 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://stormzh ...

  4. Android Studio下多渠道打包

    Android Studio下实现多渠道打包 直接上步骤 步骤 1. 清单文件添加属性(以友盟统计为例) 在application标签下添加meta-data属性 <application -- ...

  5. gradle多渠道打包及友盟统计-eclipse版本

    在进行渠道打包的之前,先看看准备篇,知道打包为了什么. 参见1.0android批量打包认知. eclipse中使用gradle多渠道打包全部流程 一.生成gradle文件,配置本地的gradle环境 ...

  6. 【转】Android Studio系列教程六--Gradle多渠道打包

    原文链接:http://stormzhang.com/devtools/2015/01/15/android-studio-tutorial6/ 由于国内Android市场众多渠道,为了统计每个渠道的 ...

  7. 【Android Studio探索之路系列】之十:Gradle项目构建系统(四):Android Studio项目多渠道打包

    作者:郭孝星 微博:郭孝星的新浪微博 邮箱:allenwells@163.com 博客:http://blog.csdn.net/allenwells github:https://github.co ...

  8. Android Studio 使用Gradle多渠道打包

    第一步:配置AndroidManifest.xml 以友盟渠道为例,渠道信息一般都是写在 AndroidManifest.xml文件中,大约如下: <meta-data android:name ...

  9. android studio学习----gradle多渠道打包

    由于国内Android市场众多渠道,为了统计每个渠道的下载及其它数据统计,就需要我们针对每个渠道单独打包,如果让你打几十个市场的包岂不烦死了,不过有了Gradle,这再也不是事了. 友盟多渠道打包 废 ...

随机推荐

  1. Ljava/lang/Iterable与AbstractMethodError

    java.lang.AbstractMethodError: com.example.demo.repository.UserRepositoryImpl.findAll()Ljava/lang/It ...

  2. Java实现POI读取Excel文件,兼容后缀名xls和xlsx

    1.引入所需的jar包: maven管理项目的话直接添加以下坐标即可: <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -- ...

  3. 转:Filter的执行顺序与实例

    转:http://www.cnblogs.com/Fskjb/archive/2010/03/27/1698448.html Filter的执行顺序与实例 Filter介绍 Filter可认为是Ser ...

  4. HDU 1561 The more, The Better【树形DP/有依赖的分组背包】

    ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物.但由于地理位置原因,有些城堡不能直接攻克,要攻克这些城堡必须先 ...

  5. 关于sql查询语句中的别名

    sql语句中给子查询或其他查询类型加别名的时候可能会报错 java.sql.SQLException: 无法转换为内部表示 原因是select返回类型的实体类中没有写该别名 原来的实体类 更改后的实体 ...

  6. Flask实战第62天:帖子详情页布局

    在templates/front/下创建详情页面front_pdetail.html 编辑front.views.py创建详情页的视图函数 from flask import abort ... @b ...

  7. Java的锁研究

    Lock和synchronized     JDK1.5以后,在锁机制方面引入了新的锁-Lock,在网上的说法都比较笼统,结合网上的信息和我的理解这里做个总结.     java现有的锁机制有两种实现 ...

  8. 【推导】【贪心】Codeforces Round #431 (Div. 1) A. From Y to Y

    题意:让你构造一个只包含小写字母的可重集,每次可以取两个元素,将它们合并,合并的代价是这两个元素各自的从‘a’到‘z’出现的次数之积的和. 给你K,你构造的可重集必须满足将所有元素合而为一以后,所消耗 ...

  9. 【数论】【中国剩余定理】【LCM】hdu1788 Chinese remainder theorem again

    根据题目容易得到N%Mi=Mi-a. 那么可得N%Mi+a=Mi. 两侧同时对Mi取余,可得(N+a)%Mi=0. 将N+a看成一个变量,就可以把原问题转化成求Mi的LCM,最后减去a即可. #inc ...

  10. Java学习笔记(12)

    eclipse使用的步骤: 1.选择工作目录.以后在Eclipse上面写的所有代码都是在工作目录上的 2.在Project Exploer窗口上新建一个工程,以后我们写代码都是以工程为单位的 3.在工 ...