本文介绍如何使用 EdgeOne 边缘函数,在边缘节点上将渠道信息注入到 APK 包中,实现边缘 APK 多渠道动态打包。
阅读本文之前,请先了解以下背景知识:
1. APK 签名原理(V1 & V2)
2. APK 多渠道包构建实现原理
3. EdgeOne 边缘函数
EdgeOne 边缘 APK 多渠道动态打包方案 与传统的 VasDolly、Walle、 ApkTool 以及 Android Gradle Plugin 方案的对比:
相比传统方案,边缘 APK 多渠道动态打包方案具备一站式动态打包与加速的能力,减小 APK 渠道包的维护难度,降低接入成本,满足业务多维度的诉求。
一、前言
在传统的 APK 多渠道打包方案中,开发者需要针对不同的渠道构建对应版本的 APK 包,这样导致 APK 渠道包数量多,难以维护。
同时,在使用 CDN 对 APK 进行下载加速时,每一个 APK 渠道包都需要各自缓存,因此会出现加速效果不均匀的问题。
本文使用 EdgeOne 边缘函数实现 边缘 APK 多渠道动态打包方案(本文简称 APK 动态打包),只需要一份 APK 包,根据下载渠道的不同,在下载时动态的注入渠道信息。同时,由于只存在一份 APK 包,也解决了 CDN 加速不均匀的问题。
二、方案设计 - APK 动态打包
APK 动态打包方案 有几个关键条件:
-
APK 包必须经过处理:无论采用何种方式,只要我们向 APK 包中注入信息,就会改变其原始数据。因此,我们需要确保处理后的 APK 仍然是一个合法的文件;
-
避免在处理 APK 包时注入渠道信息:我们需要将注入渠道信息的操作后移到下载流程,这样才能保证只有一份被处理过的 APK 包;
-
在下载 APK 包时注入渠道信息:我们需要将 "注入渠道信息" 和 "下载" 这两个操作绑定在一起。当下载操作实际发生时,将渠道信息动态地注入到 APK 包的适当位置;
如上所述,我们通过将 处理 APK 包 和 渠道信息注入 解耦,实现 动态 打包的能力,整个方案流程如图所示:
如上图所示,整个方案中存在两个关键步骤,下面分别看下每个关键步骤中,需要进行哪些操作。
2.1 APK 预处理
APK 包需要进行预处理,注入空白数据,并标记好空白数据所在位置,这样既保证了 APK 合法,又避免了过早注入专有的渠道信息。
APK 预处理流程 与 传统的多渠道构建流程 高度相似,只是将原来需要注入的 渠道信息 更换为 空白数据。
对于 V1 签名的 APK 包:
-
生成一块长度为
512
的空白数据; -
找到 EOCD 的注释区的启始位置;
-
将空白数据追加到注释区,并更新注释长度;
-
标记空白数据起始位置;
示意图如下:
对于 V2 签名的 APK 包:
-
生成一段长度为
10240
的空白数据; -
包装成符合 APK Signing Block 标准的 id-value Pair;
-
将 id-value Pair 存入 APK Signing Block 中;
-
更新 EOCD 中的相关数据(各种偏移量);
-
标记出空白数据对应的 id-value Pair 的所在位置;
示意图如下:
2.2 渠道信息动态注入
我们使用 EdgeOne 边缘函数在边缘节点进行以下操作:
-
在 HTTP 请求中获取 渠道信息;
-
找到 预处理后的 APK 包中的空白数据位置;
-
将渠道信息替换到空白数据中;
-
携带已经注入渠道信息的 APK 包响应客户端;
EgdeOne 边缘函数运行在边缘节点的 Serverless 环境中,更加贴近用户,配合 EdgeOne 缓存,可以更加快速的响应客户端。
三、方案实现 - APK 动态打包
3.1 APK 预处理
使用 COS + SCF 的方案来实现 APK 包的预处理过程,具体步骤为:
-
上传原始 APK 包至 COS 存储桶;
-
APK 包上传触发 SCF Event 函数执行:
-
获取原始 APK 包;
-
处理 APK 包,注入空白数据;
-
将处理好的 APK 包回传至客户 COS 存储桶,并将空白数据偏移量写入
response header
中;
-
详细流程如图所示:
SCF 相关代码目前不做开放,可以直接在 SCF 模版市场选择 EdgeOne APK 动态打包模版 使用。
3.2 渠道信息动态注入
使用 EdgeOne 边缘函数实现渠道信息的动态注入,具体步骤为:
-
客户端请求 APK 文件,假定请求 URL 为
https://test.com/handle.apk?comment=test
-
请求触发边缘函数执行:
-
获取
request query
参数中的comment
值; -
fetch 请求
handle.apk
文件,获取 APK 包数据和response header
中的offset
信息; -
将
comment
信息写入 APK 包的offset
位置; -
已经注入
comment
信息的 APK 包响应客户端;
-
详细流程如图所示:
边缘函数代码放在附件中。
实际函数代码中,有分片处理和流式响应相关优化,保证关键步骤的清晰,文章中没有体现。
四、部署上线 - APK 动态打包
目前,我们已经整合 COS、SCF、EdgeOne 三大产品的能力,将几个关键步骤的实现封装。只需要简单配置,就可以搭建起 APK 动态打包的工作流。
步骤1: 创建 COS 存储桶
在 COS 对象存储 中创建用于上传 APK 母包的目录(不要直接在根目录上传,建议 APK 母包上传文件夹和 APK 预处理包存储文件夹一一对应):
步骤2: 创建 SCF 云函数
为了方便使用,用于 APK 预处理的 SCF 云函数代码已经作为模版上线 SCF 模版市场。
在 云函数 SCF 通过 EdgeOne APK 动态打包的模板新建函数:
待填写信息如下:
环境变量
-
outputPath
:自定义云函数 SCF 处理 APK 母包后输出到 COS 存储桶的目录,如:/v2-vasdolly_output
; -
packVersion
:指定签名格式,取值:v1
、v2-VasDolly
、v2-Walle
、v2-Custom
; -
blockId
(可选):当packVersion
设置为v2-Custom
时,需要指定blockId
;
关于 packVersion
的取值,参照下表:
APK 签名版本 | packVersion 取值 |
---|---|
V1 | v1 |
V2 | v2-VasDolly : 将渠道信息保存在 id 为 0x881155ff (VasDolly 默认)的 id-value 对;v2-Walle :将渠道信息保存在 id 为 0x71777777 (Walle 默认)的 id-value 对;v2-Custom :将渠道信息保存在 id 为 blockId (由 blockId 环境变量指定)的 id-value 对; |
运行角色
可选择 SCF_ExecuteRole
或新建角色,确保有 COS 存储桶的读写权限:
文件系统(可选)
如果 APK 母包大于 200M,需挂载 CFS 云硬盘,如下所示:
由于 SCF 侧的限制,每个云函数在执行过程中,拥有一块 500MB 的临时磁盘空间。
处理 APK 文件时,磁盘中同时存在原始 APK 文件和处理后的 APK 文件,因此处理过大的 APK 文件,需要挂在额外的文件存储系统,详情请参见 挂载 CFS 文件系统 。
触发管理
-
触发方式:选择 COS 触发 COS Bucket,选择该可用区下母包所在的 COS 存储桶;
-
事件类型:选择全部创建;
-
前缀过滤:请输入母包上传的目录,如您的母包在 test 目录下,即填写
test/
; -
后缀过滤:请输入
.apk
;
借助 COS 和 SCF 的联动能力,APK 预处理 流程已经可以顺畅的运行起来了,在 COS 的指定目录下上传 APK 母包,经过云函数处理,在对应的 output
文件夹下可获取到云函数 SCF 处理后新的 APK 包,如下所示:
点击【详情】,在自定义 Headers 部分可查看到云函数返回的自定义 Headers:
步骤3: 创建 EdgeOne 边缘函数
通过 1、2 步的配置,我们顺利打通了 APK 预处理 的工作流程;接下来,我们需要借助 EdgeOne 边缘函数的能力,在边缘 Serverless 运行环境中,使用 JavaScript 代码实现 渠道信息动态注入。
使用 EdgeOne 边缘函数前,需要先将自己的域名接入到 EdgeOne,同时,源站配置为 APK 母包所在的存储桶:
加速域名同站点下创建边缘函数:
将附件中的边缘函数代码粘贴到代码区域,并创建函数。
内部用户还可以使用 边缘函数脚手架 TEF CLI 创建、调试、部署边缘函数代码
步骤4: 配置触发规则
部署函数后配置触发规则,其 HOST 值为之前创建的加速域名,如下所示:
步骤5: 验证效果
在浏览器中输入 URL?comment=xxxx
即可触发边缘函数,动态地将渠道信息注入到指定位置。
以 v2-VasDolly
方式为例,我们可以使用 VasDolly 工具来读取动态注入的渠道信息:
五、总结
EdgeOne 边缘函数拥有 分布式部署、贴近用户、超低延迟、弹性扩容、Serverless 环境 等优势,借助 EdgeOne 边缘函数,我们成功实现了边缘 APK 多渠道动态打包方案。
APK 动态打包工作流打通后,开发者无需再关注其他操作,只需要简单两步,即可实现多渠道包的构建,降低了 APK 渠道包的维护、使用难度。
同时,业务源站(COS)只需存放一个 APK 预处理包,解决了大量 APK 渠道包托管问题,降低了业务成本。
更重要的是,边缘 APK 多渠道动态打包方案借助边缘函数独特的建构优势,配合 EdgeOne 缓存,优化了 APK 渠道包的下载体验,优化用户体验、提高用户留存。