当项目须要有更多的客户的时候,你就会考虑将apk上架到应用商店了,无奈天朝Android应用商店真的是百家争鸣,据某地不彻底统计已经有900+。若将Apk上架到全部的应用商店是个好主意,可是据统计也就那么十来个应用商店的占有率已经超过95%了,因此我以为并无必要上架全部应用商店。这里就比如Android里面适配机型一个道理,机型无数,可是也就那么几个品牌占有的绝大多数市场。html
话说回来为何要打渠道包(好比说应用宝要发一个apk,小米应用商店要发一个apk等等),而不是同一个apk放到每个应用商店呢?主要有下列缘由:java
1. 不一样的应用商店对于apk的要求不一样,有的甚至须要一些定制,好比某些应用商店要求在启动页加入商店的Logoandroid
2. 为了跟踪每家应用商店的用户数等等统计数据app
幸运的是gradle天生就提供了打多渠道包的功能,这里咱们主要解决下列问题:函数
修改build.gradle和预编译BuildConfig类解析gradle
在moudle的build.gradle的android元素下,有这么productFlavors这么一个函数,它支持不一样“口味”的版本编译。好比咱们须要作一个应用宝的渠道版本,能够添加下列代码:ui
android { productFlavors { YingYongBao { manifestPlaceholders = [UMENG_CHANNEL:"YingYongBao"] buildConfigField "String", "CHANNEL", "\"YingYongBao\"" } }
随后在AndroidManifest.xml的配置友盟渠道号的地方改为:spa
<meta-data android:name="UMENG_CHANNEL" android:value="${UMENG_CHANNEL}" />
productFlavors中的manifestPlaceholder相似于给AndroidManifest文件定义了一个变量,上述例子中改变量名字就加UMENT_CHANNEL,值为字符串YingYongBao,这样子改渠道打包出来的apk便可以发布到应用宝市场上了。同时你在友盟的后台统计模块控制台中,也能够看到一个叫作“YingYongBao”的渠道来源,能够跟踪该渠道的用户使用数据。这样咱们要解决的第2个问题OK了。.net
productFlavors中的buildConfigField是在等于在预编译期间建立了一个变量叫作CHANNEL,类型是字符串类型,值是字符串“YingYongBao”。debug
当咱们写C/C++代码的时候一般会写预编译宏变量,能够控制代码中在不一样编译条件下的执行分支。好比:
#ifdef _MACRO_YING_YONG_BAO { // code for yingyongbao } #else { // code for others } #endif
当须要执行应用宝那部分代码的时候则编译时打开宏_MACRO_YING_YONG_BAO。而Android Studio也提供了相似的机制,它在预编译阶段生成了一个叫作BuildConfig.java的类,它位于:
当咱们预编译时会自动生成这么一个类,按照上述编译应用宝渠道的操做中,咱们看下这个BuildConfig.java是什么内容:
这里发现有一个叫作CHANNEL的String常量,并且值是“YingYongBao”,因此想到那么这里为了让不一样渠道执行不一样的代码,咱们因而能够在代码中这样子写:
if (BuildConfig.CHANNEL.equals("YingYongBao")) { // code block for yingyongbao } else if (BuildConfig.CHANNEL.equals("360") { // code block for 360 } else { // default code }
这里须要注意的一点,经过buildConfigField定义的变量中,若是是String类型的话,必需要在值里面写上转义符号\",或者写成:
buildConfigField "String", "CHANNEL", ‘"YingYongBao"’
不然的话预编译器会认为YingYongBao不是一个值而是另外一个变量,从而报错:
到此,第3个问题也解决了!
在Android Studio中一键打包
到如今尚未说如何打包的事情,这点很简单,只要打开Android Studio的gradle面板,刷新task列表,会发现不少task,只要双击下assembleRelease这个task便可。稍等一段时间,Android Studio自动帮你生成全部的渠道的Apk。
生成的全部apk在这里:
这里有两个注意点:
问题1解决
多包名支持
在build.gradle中是用applicationId来表述包名的,在productFlavors中是能够嵌入applicationId的定义,好比咱们在Beta这样的渠道中想要打出一个com.qianmi.xxx.beta的包名的apk,能够这么写:
productFlavors { Beta { manifestPlaceholders = [UMENG_CHANNEL:"Beta"] buildConfigField "String", "CHANNEL", "\"Beta\"" applicationId "com.qianmi.xxx.beta" } }
问题4解决
BuildConfig的一种有意思的用法(彩蛋)
咱们知道发布出去的apk都是带有签名的,而从Android Studio等IDE中直接run到手机上的是没有签名的,可是两个手机,一台装了签名的apk一台是直接run上去的,你能区分出来吗(实际是看不出来的)?
若是咱们能动态的区分出来,同时对于直接从IDE运行出来的Apk中在app的某个界面(好比关于界面)有下列标志多好?
而在正式发布出来的版本中没有“开发版本”这个字串。
首先咱们在build.gradle中的android元素下的buildTypes函数中加入:
buildTypes { release { minifyEnabled true zipAlignEnabled true shrinkResources true signingConfig signingConfigs.release proguardFiles 'proguard-rules.pro' } debug { minifyEnabled false zipAlignEnabled true shrinkResources true buildConfigField "String", "CHANNEL", "\"dev\"" } }
这里有一个release和一个debug。当你经过上述讲解中的gradle task中打包时是release,打包时读取具体的productFlavors。而若是你是直接从IDE运行出来调试的话,会检查buildTypes中debug这个地方,这里咱们一样把CHANNEL这个常量给定义出来了,值是dev。
因而咱们再在关于界面,写上下列语句便可:
if (BuildConfig.CHANNEL.equals("dev")) { tvVersion.setText("v" + AppUtils.getVersionName(getApplicationContext()) + " " + getString(R.string.dev_version)); } else { tvVersion.setText("v" + AppUtils.getVersionName(getApplicationContext())); }
题外话
到此为止,多渠道打包问题已经解决。可是打包的时候发现若是渠道越多实际上打包的时间是越慢的,由于Android Studio在为每一个渠道一个个的生成apk,因此咱们这里提供的方式仅仅适用于渠道比较少的状况下。若是你真的想要在900个以上的应用市场发布大家的apk,那么显然这种方式就不行了。这里提供两个解决方法。
一个是对同一个base的apk进行修改的方式,能够参考美团技术团队的博客:
http://tech.meituan.com/mt-apk-packaging.html
或者
http://blog.csdn.net/luck_apple/article/details/8634572?utm_source=tuicool&utm_medium=referral
第二个是试用一些厂商的支持多渠道打包的软件,好比360的加固宝:
文末附上一家统计公司提供的国内应用市场占有率的报告:
转载请注明出处: http://www.cnblogs.com/soaringEveryday/p/5368540.html