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

相关文章

Debezium 与 Apache Kafka 的集成方式步骤详解

《Debezium与ApacheKafka的集成方式步骤详解》本文详细介绍了如何将Debezium与ApacheKafka集成,包括集成概述、步骤、注意事项等,通过KafkaConnect,D... 目录一、集成概述二、集成步骤1. 准备 Kafka 环境2. 配置 Kafka Connect3. 安装 D

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

SQL 中多表查询的常见连接方式详解

《SQL中多表查询的常见连接方式详解》本文介绍SQL中多表查询的常见连接方式,包括内连接(INNERJOIN)、左连接(LEFTJOIN)、右连接(RIGHTJOIN)、全外连接(FULLOUTER... 目录一、连接类型图表(ASCII 形式)二、前置代码(创建示例表)三、连接方式代码示例1. 内连接(I

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

JS 实现复制到剪贴板的几种方式小结

《JS实现复制到剪贴板的几种方式小结》本文主要介绍了JS实现复制到剪贴板的几种方式小结,包括ClipboardAPI和document.execCommand这两种方法,具有一定的参考价值,感兴趣的... 目录一、Clipboard API相关属性方法二、document.execCommand优点:缺点:

Python创建Excel的4种方式小结

《Python创建Excel的4种方式小结》这篇文章主要为大家详细介绍了Python中创建Excel的4种常见方式,文中的示例代码简洁易懂,具有一定的参考价值,感兴趣的小伙伴可以学习一下... 目录库的安装代码1——pandas代码2——openpyxl代码3——xlsxwriterwww.cppcns.c