由于国内存在着有众多的应用市场,在不同的应用市场可能有不同的统计需求,为此Android开发人员需要为每个应用市场发布一个安装包,这里就引出了Android的多渠道打包。在安装包中添加不同的标识,以此区分各个渠道,方便统计app在市场的各种效果。
因此,每当发新版本时,市场会提供一个渠道列表,Android RD会根据这些渠道相应地生成等量的渠道包。随着渠道越来越多,为了提高渠道打包的效率,因此催生了对多渠道打包的方式的研究。
本篇文章主要总结一下多渠道打包的相关知识以及美团的新旧两种多渠道打包方案。
Maven方式: 每打一个包都要执行一遍构建过程,效率太低;
apktool: 虽然不需要重新构建,但对每个包都要重新签名;
随着渠道包的增多,每次打包动辄几个小时,以上两种方式的效率太低。
关于这两种打包方式详见:美团Android自动化之旅—生成渠道包
META-INF
添加空文件这是美团为了提高打包效率而提出的一种新的多渠道打包方式,不需要重新构建,也不需要重新签名。
通过解压apk,根目录下会有一个META-INF
目录,在该目录下添加空文件,可以不用重新签名应用。因此,通过为不同渠道的应用添加不同的空文件,可以唯一标识一个渠道。
利用python代码用来给apk添加空的渠道文件
在Java代码中读取空渠道文件名,识别渠道
具体代码在上面美团生成多渠道包的链接中有详细给出。
Walle(瓦力):Android Signature V2 Scheme签名下的新一代渠道包打包神器
瓦力通过在Apk中的APK Signature Block
区块添加自定义的渠道信息来生成渠道包,从而提高了渠道包生成效率,可以作为单机工具来使用,也可以部署在HTTP服务器上来实时处理渠道包Apk的升级网络请求。
Android 7.0(Nougat)引入一项新的应用签名方案APK Signature Scheme v2,它是一个对全文件进行签名的方案,能提供更快的应用安装时间、对未授权APK文件的更改提供更多保护,在默认情况下,Android Gradle 2.2.0插件会使用APK Signature Scheme v2和传统签名方案来签署你的应用。
新应用签名方案的签名信息会被保存在区块(APK Signing Block
)中, 而区块(Contents of ZIP entries
)、区块(ZIP Central Directory
)、区块(ZIP End of Central Directory
)是受保护的,在签名后任何对其的修改都逃不过新的应用签名方案的检查。
之前的渠道包生成方案是通过在META-INF
目录下添加空文件的打包方式在Signature Scheme v2的签名方式下不可使用了,因为META-INF
已经被列入了保护区了,向META-INF
添加空文件的方案会对上面受保护的三个区块都有影响。
通过上面描述发现区块(APK Signing Block
)是不受签名校验规则保护的,因此Walle正是通过在该区块做文章,写入渠道信息。
对新的应用签名方案生成的APK包中区块(APK Signing Block
)写入渠道信息,并保存在APK中
APK在安装过程中进行的签名校验,是忽略我们添加的渠道信息的,这样就能正常安装了
在App运行阶段,可以通过ZIP的End of central directory
、Central directory
等结构中的信息找到我们自己添加的渠道信息,从而实现获取渠道信息的功能
最终,每打一个渠道包只需复制一个APK,然后在APK中添加一个渠道信息即可,这种打包方式速度非常快。
Gradle插件方式,方便快速集成
命令行方式,最大化满足各种自定义需求
关于Walle两种使用方式的详细步骤,参见:Android使用walle多渠道打包
上述多渠道打包方式解决了打包慢的问题,但是随着渠道越来越多,不同渠道对应用的要求也不尽相同。
例如,有的渠道要求app的应用名不同,有些渠道要求应用不能使用第三方统计工具,有些渠道要求应用不能自动更新。
之前的做法是为每个需要适配的渠道创建一个Git分支,发版时再切换到相应的分支,并合并主分支的代码。适配的渠道比较少的话这种方式还可以接受,随着适配渠道的增多,这种方式就变得不可取。
幸好Gradle flavor,可以满足渠道适配的需求,只需要通过配置Gradle即可以实现多渠道的适配工作,省心省力。
先来看build.gradle
文件中的一段代码:
android {
....
productFlavors {
flavor1 {
minSdkVersion 14
}
}
}
上例定义了一个flavor
:flavor1
,并指定了应用的minSdkVersion
为14(当然还可以配置更多的属性,具体可参考相关文档)。与此同时,Gradle还会为该flavor
关联对应的sourceSet
,默认位置为src/
目录,对应到本例就是src/flavor1
。
接下来,要做的就是根据具体的需求在build.gradle
文件中配置flavor
,并添加必要的代码和资源文件。以flavor1
为例,运行gradle assembleFlavor1
命令既可生成所需的适配包。通过适配不同的flavor
即可以生成不同的渠道包,但该方式生成渠道包的方式需要重复编译构建。
productFlavors {
qq {
applicationId "com.hello.group.qq"
}
}
面的代码添加了一个名为qq
的flavor,并指定了应用的包名为com.hello.group.qq
,运行gradle assembleqq
命令即可生成qq适配包。
Gradle在构建应用时,会优先使用flavor
所属sourceSet
中的同名资源。所以,解决思路就是在flavor
的sourceSet
中添加同名的字符串资源,以覆盖默认的资源。
首先,在build.gradle
配置文件中添加如下flavor:
android {
productFlavors {
wandoujia {
}
}
}
上面的配置会默认src/wandoujia
目录为wandoujia
flavor的sourceSet
。
接下来,在src
目录内创建wandoujia
目录,并添加如下应用名字符串资源(src/wandoujia/res/values/appname.xml
):
<resources>
<string name="app_name">wandoujia_appstring>
resources>
默认的应用名字符串资源如下(src/main/res/values/strings.xml
):
<resources>
<string name="app_name">origin_appstring>
resources>
最后,运行gradle assembleWandoujia
命令即可生成应用名为wandoujia_app
的应用了。
wandoujia包下不使用strings.xml 名是因为会出现文件重复,默认的main 文件夹里存在的文件在其他适配目录中不允许出现相同文件名的文件。
更多flavor
适配示例,参见:美团Android自动化之旅—适配渠道包
以上就是最近了解关于多渠道打包的相关知识的总结。
想要实现更多自定义适配多渠道包的需求,还要更多的了解Gradle相关知识。