android 中三种多渠道打包方式

2024-06-19 13:18

本文主要是介绍android 中三种多渠道打包方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://gold.xitu.io/entry/578c98826be3ff006ce78317

http://gold.xitu.io/entry/578c98826be3ff006ce78317

android 中三种多渠道打包方式

转载请标明出处:一片枫叶的专栏

国内的Android开发者还是很苦逼的,由于众所周知的原因,google play无法再国内打开,所以android系的应用市场,群雄争霸,而后果就是国内存在着有众多的应用市场,产品在不同的渠道可能有这不同的统计需求,为此android开发人员需要为每个应用市场发布一个安装包,这里就涉及到了android的多渠道打包。

本文主要讲解的就是几种主流的多渠道打包方式,以及其优劣势。

这种打包方式是使用android Studio的编译工具gradle配合使用的,其核心原理就是通过脚本修改androidManifest.xml中的mate-date内容,执行N次打包签名操作实现多渠道打包的需求,具体实现如下。

(一)在androidmanifest.xml中定义mate-data标签

<manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="your.package.name">    <application>    <meta-data android:name="UMENG_CHANNEL" android:value="{UMENG}"/>    </application>    
</manifest>  

这里需要注意的是:上面的value的值要和渠道名所对应,比如wandoujia里面要对应为你豌豆荚的渠道名称

(二)在build.gradle下的productFlavors定义渠道号:

productFlavors {  internal {}  /*InHouse {}  pcguanwang {}  h5guanwang {}  hiapk {}  m91 {}  appchina {}  baidu {}  qq {}  jifeng {}  anzhi {}  mumayi {}  m360 {}  youyi {}  wandoujia {}  xiaomi {}  sougou {}  leshangdian {}  huawei {}  uc {}  oppo {}  flyme {}  jinli {}  letv {}*/  productFlavors.all { flavor ->  flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]  }  }    

同时需要注意的是,这里需要在defaultConfig中配置一个默认的渠道名称

manifestPlaceholders = [UMENG_CHANNEL_VALUE: "channel_name"]  

实现多渠道打包更换mate-data标签中的内容

优势:方便灵活,可以根据自身的需求配置不同的渠道执行不同的逻辑; 
劣势:打包速度过慢;

这种方式就是使用第三方的服务,比如360,百度,友盟等,其原理也是通过修改androidManifest.xml中的mate-data标签内容,然后执行N次打包签名的操作实现多渠道打包的。这里就不在做具体解释说明,免得又做广告的嫌疑,O(∩_∩)O哈哈~。

优势:简单方便,几乎不用自身做什么工作; 
劣势:打包速度过慢;

而这里主要是根据美团客户端打包经验(详见:美团Android自动化之旅—生成渠道包) 
主要是介绍利用在META-INF目录内添加空文件的方式,实现批量快速打包Android应用。

实现原理

Android应用安装包apk文件其实是一个压缩文件,可以将后缀修改为zip直接解压。解压安装文件后会发现在根目录有一个META-INF目录。如果在META-INF目录内添加空文件,可以不用重新签名应用。因此,通过为不同渠道的应用添加不同的空文件,可以唯一标识一个渠道。 
“采用这种方式,每打一个渠道包只需复制一个apk,在META-INF中添加一个使用渠道号命名的空文件即可。这种打包方式速度非常快,900多个渠道不到一分钟就能打完。”

实现步骤

(一)编写渠道号文件

(二)编写python脚本,实现解压缩apk文件,为META-INF目录添加文件,重新压缩apk文件等逻辑:


# coding=utf-8
import zipfile
import shutil
import osdef delete_file_folder(src):  '''delete files and folders''' if os.path.isfile(src):  try:  os.remove(src)  except:  pass elif os.path.isdir(src):  for item in os.listdir(src):  itemsrc=os.path.join(src,item)  delete_file_folder(itemsrc)  try:  os.rmdir(src)  except:  pass# 创建一个空文件,此文件作为apk包中的空文件
src_empty_file = 'info/empty.txt'
f = open(src_empty_file,'w')
f.close()# 在渠道号配置文件中,获取指定的渠道号
channelFile = open('./info/channel.txt','r')
channels = channelFile.readlines()
channelFile.close()
print('-'*20,'all channels','-'*20)
print(channels)
print('-'*50)# 获取当前目录下所有的apk文件
src_apks = [];
for file in os.listdir('.'):if os.path.isfile(file):extension = os.path.splitext(file)[1][1:]if extension in 'apk':src_apks.append(file)# 遍历所以的apk文件,向其压缩文件中添加渠道号文件
for src_apk in src_apks:src_apk_file_name = os.path.basename(src_apk)print('current apk name:',src_apk_file_name)temp_list = os.path.splitext(src_apk_file_name)src_apk_name = temp_list[0]src_apk_extension = temp_list[1]apk_names = src_apk_name.split('-');output_dir = 'outputDir'+'/'if os.path.exists(output_dir):delete_file_folder(output_dir)if not os.path.exists(output_dir):os.mkdir(output_dir)# 遍历从文件中获得的所以渠道号,将其写入APK包中for line in channels:target_channel = line.strip()target_apk = output_dir + apk_names[0] + "-" + target_channel+"-"+apk_names[2] + src_apk_extensionshutil.copy(src_apk,  target_apk)zipped = zipfile.ZipFile(target_apk, 'a', zipfile.ZIP_DEFLATED)empty_channel_file = "META-INF/uuchannel_{channel}".format(channel = target_channel)zipped.write(src_empty_file, empty_channel_file)zipped.close()print('-'*50)
print('repackaging is over ,total package: ',len(channels))
input('\npackage over...')

(三)打包一个正常的apk包 
(四)执行python脚本,多渠道打包 
(五)android代码中获取渠道号

/*** 渠道号工具类:解析压缩包,从中获取渠道号*/
public class ChannelUtil {private static final String CHANNEL_KEY = "uuchannel";private static final String DEFAULT_CHANNEL = "internal";private static String mChannel;public static String getChannel(Context context) {return getChannel(context, DEFAULT_CHANNEL);}public static String getChannel(Context context, String defaultChannel) {if (!TextUtils.isEmpty(mChannel)) {return mChannel;}//从apk中获取mChannel = getChannelFromApk(context, CHANNEL_KEY);if (!TextUtils.isEmpty(mChannel)) {return mChannel;}//全部获取失败return defaultChannel;}
   /*** 从apk中获取版本信息** @param context* @param channelKey* @return*/private static String getChannelFromApk(Context context, String channelKey) {long startTime = System.currentTimeMillis();//从apk包中获取ApplicationInfo appinfo = context.getApplicationInfo();String sourceDir = appinfo.sourceDir;//默认放在meta-inf/里, 所以需要再拼接一下String key = "META-INF/" + channelKey;String ret = "";ZipFile zipfile = null;try {zipfile = new ZipFile(sourceDir);Enumeration<?> entries = zipfile.entries();while (entries.hasMoreElements()) {ZipEntry entry = ((ZipEntry) entries.nextElement());String entryName = entry.getName();if (entryName.startsWith(key)) {ret = entryName;break;}}} catch (IOException e) {e.printStackTrace();} finally {if (zipfile != null) {try {zipfile.close();} catch (IOException e) {e.printStackTrace();}}}String channel = "";if (!TextUtils.isEmpty(ret)) {String[] split = ret.split("_");if (split != null && split.length >= 2) {channel = ret.substring(split[0].length() + 1);}System.out.println("-----------------------------");System.out.println("渠道号:" + channel + ",解压获取渠道号耗时:" + (System.currentTimeMillis() - startTime) + "ms");System.out.println("-----------------------------");} else {System.out.println("未解析到相应的渠道号,使用默认内部渠道号");channel = DEFAULT_CHANNEL;}return channel;}
}

整个打包的流程就是这样了,打工工具可参考github上的项目:多渠道打包实现

优势:打包速度很快,很方便; 
劣势:不够灵活,不能灵活的配置不同的渠道不同的业务逻辑;

问题: 
项目中由于使用了友盟统计,以前是在meta-data中保存渠道信息,现在更改了方式之后需要手动执行渠道号的设置代码:

String channel = ChannelUtil.getChannel(mContext)System.out.println("启动页获取到的渠道号为:" + channel)// 设置友盟统计的渠道号,原来是在Manifest文件中设置的meta-data,现在启动页中设置AnalyticsConfig.setChannel(channel)

通过这种打包方式以前需要一个小时的打包工作现在只需要一分钟即可,极大的提高了效率,目前在实际的应用中尚未发现有什么问题,有这种需求的童鞋可以尝试一下。

虽说我们总结了三种打包方式,但是其实通过gradle打包和使用第三方服务打包都是执行了N次的打包签名操作,时间上耗费太多,因此不太推荐,而美团的方式在效率上提高了很多,但是对于那种不同的渠道包执行不同的业务逻辑的需求就无能为例了,只能通过gradle配置,因此大家在选择多渠道打包方式的时候可以根据自身的需求来选择。

另外对产品研发技术,技巧,实践方面感兴趣的同学可以参考我的: 
android产品研发–>总结(持续更新) 
android产品研发(一)–>实用开发规范 
android产品研发(二)–>启动页优化 
android产品研发(三)–>基类Activity 
android产品研发(四)–>减小Apk大小

本文以同步至github中:https://github.com/yipianfengye/androidProject,欢迎star和follow


这篇关于android 中三种多渠道打包方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1075136

相关文章

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配

JavaScript对象转数组的三种方法实现

《JavaScript对象转数组的三种方法实现》本文介绍了在JavaScript中将对象转换为数组的三种实用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友... 目录方法1:使用Object.keys()和Array.map()方法2:使用Object.entr

Vue3视频播放组件 vue3-video-play使用方式

《Vue3视频播放组件vue3-video-play使用方式》vue3-video-play是Vue3的视频播放组件,基于原生video标签开发,支持MP4和HLS流,提供全局/局部引入方式,可监听... 目录一、安装二、全局引入三、局部引入四、基本使用五、事件监听六、播放 HLS 流七、更多功能总结在 v

Python打包成exe常用的四种方法小结

《Python打包成exe常用的四种方法小结》本文主要介绍了Python打包成exe常用的四种方法,包括PyInstaller、cx_Freeze、Py2exe、Nuitka,文中通过示例代码介绍的非... 目录一.PyInstaller11.安装:2. PyInstaller常用参数下面是pyinstal

Java发送SNMP至交换机获取交换机状态实现方式

《Java发送SNMP至交换机获取交换机状态实现方式》文章介绍使用SNMP4J库(2.7.0)通过RCF1213-MIB协议获取交换机单/多路状态,需开启SNMP支持,重点对比SNMPv1、v2c、v... 目录交换机协议SNMP库获取交换机单路状态获取交换机多路状态总结交换机协议这里使用的交换机协议为常

nodejs打包作为公共包使用的完整流程

《nodejs打包作为公共包使用的完整流程》在Node.js项目中,打包和部署是发布应用的关键步骤,:本文主要介绍nodejs打包作为公共包使用的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言一、前置准备二、创建与编码三、一键构建四、本地“白嫖”测试(可选)五、发布公共包六、常见踩坑提醒

k8s admin用户生成token方式

《k8sadmin用户生成token方式》用户使用Kubernetes1.28创建admin命名空间并部署,通过ClusterRoleBinding为jenkins用户授权集群级权限,生成并获取其t... 目录k8s admin用户生成token创建一个admin的命名空间查看k8s namespace 的

uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)

《uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)》在uni-app开发中,文件上传和图片处理是很常见的需求,但也经常会遇到各种问题,下面:本文主要介绍uni-app小程序项目中实... 目录方式一:使用<canvas>实现图片压缩(推荐,兼容性好)示例代码(小程序平台):方式二:使用uni

Pandas处理缺失数据的方式汇总

《Pandas处理缺失数据的方式汇总》许多教程中的数据与现实世界中的数据有很大不同,现实世界中的数据很少是干净且同质的,本文我们将讨论处理缺失数据的一些常规注意事项,了解Pandas如何表示缺失数据,... 目录缺失数据约定的权衡Pandas 中的缺失数据None 作为哨兵值NaN:缺失的数值数据Panda