首页 > 技术文章 > Android一键多渠道分发打包实战和解析

soaringEveryday 2016-04-08 16:04 原文

当项目需要有更多的客户的时候,你就会考虑将apk上架到应用商店了,无奈天朝Android应用商店真的是百家争鸣,据某地不完全统计已经有900+。若将Apk上架到所有的应用商店是个好主意,但是据统计也就那么十来个应用商店的占有率已经超过95%了,所以我觉得并没有必要上架所有应用商店。这里就好比Android里面适配机型一个道理,机型无数,但是也就那么几个品牌占有的绝大多数市场。

话说回来为什么要打渠道包(比如说应用宝要发一个apk,小米应用商店要发一个apk等等),而不是同一个apk放到每一个应用商店呢?主要有下列原因:

1. 不同的应用商店对于apk的要求不同,有的甚至需要一些定制,比如某些应用商店要求在启动页加入商店的Logo

2. 为了跟踪每家应用商店的用户数等等统计数据

幸运的是gradle天生就提供了打多渠道包的功能,这里我们主要解决下列问题:

  • 如何打多个渠道的包
  • 如何支持友盟统计
  • 如何在代码中根据不同渠道做执行不同的代码块,即渠道定制
  • 如何支持多包名打包
  • 一种对于BuildConfig的更有意思的用法(彩蛋)

 

修改build.gradle和预编译BuildConfig类解析


 

在moudle的build.gradle的android元素下,有这么productFlavors这么一个函数,它支持不同“口味”的版本编译。比如我们需要做一个应用宝的渠道版本,可以添加下列代码:

android {
    productFlavors {
        YingYongBao {
            manifestPlaceholders = [UMENG_CHANNEL:"YingYongBao"]
            buildConfigField "String", "CHANNEL", "\"YingYongBao\""
        }
}

随后在AndroidManifest.xml的配置友盟渠道号的地方改成:

<meta-data
            android:name="UMENG_CHANNEL"
            android:value="${UMENG_CHANNEL}" />

productFlavors中的manifestPlaceholder类似于给AndroidManifest文件定义了一个变量,上述例子中改变量名字就加UMENT_CHANNEL,值为字符串YingYongBao,这样子改渠道打包出来的apk即可以发布到应用宝市场上了。同时你在友盟的后台统计模块控制台中,也可以看到一个叫做“YingYongBao”的渠道来源,可以跟踪该渠道的用户使用数据。这样我们要解决的第2个问题OK了。

 

productFlavors中的buildConfigField是在等于在预编译期间创建了一个变量叫做CHANNEL,类型是字符串类型,值是字符串“YingYongBao”。

当我们写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. 执行打包前,最好先执行下clean那个task
  2. build那个task也可以打所有渠道的包,但是比较慢,因为它同时也打出来debug包,而assembleRelease只打release包,理论上减少一半时间

问题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://jiagu.360.cn/

 

文末附上一家统计公司提供的国内应用市场占有率的报告:

转载请注明出处: http://www.cnblogs.com/soaringEveryday/p/5368540.html

推荐阅读