qrcode

马上订阅,开启修仙之旅

在前端 IPA & APK 还能这样玩

一、背景概述

近期公司为了方便管理内部多个不同版本的测试包,打算在公司内部搭建一个类似蒲公英/fir.im 的安装包管理平台。经过本人的一番搜索在 Github 上发现了 fabu.love 这个项目,基于该项目搭建的应用发布平台,可支持安装包管理、检查更新,灰度发布等功能。此外该项目采用前后端分离的开发方式进行开发,前端技术栈采用 Vue + Element UI,后端技术栈采用 Node.js + Koa,这对于我这个伪全栈来说是一个不错的选择。

fabu.love 这个项目提供 Docker 和源码部署两种方式,作者推荐使用 Docker 方式进行部署,为了快速验证平台效果,本人也是采用 Docker 方式部署。在公司一些小伙伴的配合下,我们完成了第一阶段的测试,得出的结论是基本能满足公司内部的需求。但把结果汇报给 Boss 之后,Boss 又提出了一个需求,若公司目前使用的付费应用分发平台出现异常时,fabu.love 这个平台能否在关键的时刻顶上。对于这个问题,当时我无法给出明确的答复,因为那时我对该项目并没有深入了解且该平台也未经过深度的测试。为了能给出一个较为明确回复,我开始了 fabu.love 项目的源码之旅。

二、项目分析

经过对 fabu.love 源码一番研读之后,发现该项目若要作为第三方平台的“备胎”,提前要先解决以下几个问题:

  • 上传的包存在分发平台所在的服务器上,当并发量高的时候,肯定扛不住;
  • iOS 企业证书版安装时使用的 itms-services 协议对应的 plist 文件(XML 类型)是通过服务端渲染生成的,此外应用下载页使用的是短网址,也是需要在服务端做处理,高并发的时候也会存在问题;
  • 应用下载页面未对下载进行验证并限制下载地址的有效期,无法防止恶意下载。

针对前面的两个问题,通过修改项目的源码,我们都已经解决了,主要的解决方案是等安装包上传成功并成功解析后,把安装包和 iOS 平台对应的 plist 文件同步上传到第三方云存储,比如七牛云。对于第三个问题,我们也初步制定了处理方案。在研读该项目源码的过程中,发现了一个用于解析安装包的插件 —— app-info-parser,接下来我们来介绍一下 app-info-parser。

三、app-info-parser 简介

app-info-parser 是一个解析器用于解析 .ipa.apk 文件。当解析完成后,它会以 JSON 的形式返回 AndroidManifest.xmlInfo.plist 文件中的内容。该解析插件同时支持 Node.js 和浏览器平台。

app-info-parser-browser-support

3.1 安装 app-info-parser

1
2
3
npm install app-info-parser
# or yarn
yarn add app-info-parser

3.2 Node.js 使用示例

1
2
3
4
5
6
7
8
9
const AppInfoParser = require('app-info-parser')
const parser = new AppInfoParser('../packages/test.apk') // or xxx.ipa

parser.parse().then(result => {
console.log('app info ----> ', result)
console.log('icon base64 ----> ', result.icon)
}).catch(err => {
console.log('err ----> ', err)
})

除了导入 AppInfoParser 解析器之外,在使用过程中还可以按需导入 IPA 或 APK 安装包的解析器,具体可以参考 app-info-parser 说明文档。

3.3 浏览器使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<input type="file" name="file" id="file" onchange="fileSelect()">
<script src="/dist/app-info-parser.js"></script>
<script>
function fileSelect () {
const files = document.getElementById('file').files
const parser = new AppInfoParser(files[0])
parser.parse().then(result => {
console.log('app info ----> ', result)
console.log('icon base64 ----> ', result.icon)
}).catch(err => {
console.log('err ----> ', err)
})
}
</script>

fabu.love 是在后台对安装包进行解析,为了加快用户下载的速度并减少对发布平台的压力,我们还需要把安装包再次上传到第三方云存储,这样的话安装包就需要两次传输。如果在前端解析安装包的话,就可以在成功解析和成功上传之后,再把安装包的信息和对应的下载地址一次性提交到后端。

四、iOS itms-services 协议

itms-service 是 Apple 为 iOS 企业用户提供的无线分发安装方式所使用的协议,使用这种方式发布应用不需要通过 App Store,任何 iOS 设备都可以安装企业用户通过这种方式发布的应用而没有设备数目的限制。itms-service 协议的格式如下:

1
itms-services://?action=download-manifest&url=http://domain/ios/manifest.plist

基于该协议用户就可以从 Safari 浏览器直接打开上述格式的 itms-services 协议的链接,即可在 iOS 设备上直接安装链接所指向的应用。协议中的 url 参数指向的是一个 plist 文件的 url 链接,该文件是一个 XML 格式的配置文件,以下是 iOS 安装包的 plist 文件模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>{{{ downloadUrl }}}</string>
<key>md5-size</key>
<integer>{{{ fileSize }}}</integer>
</dict>
<dict>
<key>kind</key>
<string>display-image</string>
<!-- optional. indicates if icon needs shine effect applied. -->
<key>needs-shine</key>
<true/>
<key>url</key>
<string>{{{ iconUrl }}}</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>{{{ bundleID }}}</string>
<key>bundle-version</key>
<string>{{{ versionStr }}}</string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string>{{{ appName }}}</string>
</dict>
</dict>
</array>
</dict>
</plist>

在 fabu.love 项目中是通过 mustache 模板引擎来动态生成 iOS 应用所对应的 plist 文件。

五、总结

本文介绍了 fabu.love 应用发布平台和 app-info-parser Apk 和 Ipa 应用包解析插件,除此之外还介绍了 iOS itms-services 协议。对应用发布平台感兴趣的小伙伴,可以参考一下 fabu.love 这个项目,如果遇到问题的话,欢迎一起讨论。

六、参考资源


欢迎小伙伴们订阅前端全栈修仙之路,及时阅读 Angular、TypeScript、Node.js/Java和Spring技术栈最新文章。

qrcode