|
|
3 weeks ago | |
|---|---|---|
| .. | ||
| README.md | 3 weeks ago | |
| build.sh | 3 weeks ago | |
| download.html | 3 weeks ago | |
| index.template.html | 3 weeks ago | |
README.md
下载落地页(dl.ymaikj.com)
⚠️ 2026-09-23 起线上页面由管理后台维护:「服务配置 → 版本与分发 → 下载页」编辑/保存/查看, 直接发布到
ymai-dl/<应用>/download.html。本目录只作初始模板,改这里不会生效, 拿这里的文件手传 OSS 会覆盖后台改过的版本。
一个纯静态页,托管在阿里云 OSS 上,不占服务器、不经 NPM。 安装包也放同一个桶里,页面按 UA 决定跳商店还是给 APK 直链。
deploy/dl/
├── index.template.html ← 源文件,改页面改这个
├── build.sh ← 把 App 图标内联进去,生成 index.html
└── index.html ← 生成物,**上传的是它**(已入库,方便直接传)
版本号、更新日志、各商店链接都不在页面里维护,实时取自管理后台(见下文「三」)。
图标取自 apps/client/assets/images/app_icon.png,与 App 用的是同一份素材。
一、为什么放 OSS 而不是放业务服务器
下载页一般要挂 APK 直链。微信、各家浏览器对「发 apk 的域名」判定很粗暴,
一旦被拦截或标记为风险,同域名上的接口请求也会一起遭殃。所以它必须与
ym.ymaikj.com(业务网关)分开。
放 OSS 还有两个顺带好处:页面和安装包同源(没有跨域、没有防盗链问题), 以及不占业务机的带宽——一个版本几十 MB,几千次下载就是几百 GB。
二、部署步骤(首次)
✅ 2026-09-23:
ymai-dl桶、dl.ymaikj.com域名与证书均已建好并实测可用 (证书有效期至 2027-03-23,404 路由正确,与ym.ymaikj.com的跨域也已实测通过)。 下面三步留档,重建时照做。
1. 准备存储桶
建议新建一个专用桶,例如 ymai-dl(上海,与 ymaioss 同地域):
- 读写权限:公共读(安装包本来就要公开下载)
- 不要复用
ymaioss。那个桶里是用户录音,把公开分发的东西混进去会让 权限、生命周期规则、流量账单都分不清谁是谁。
想省事复用
ymaioss也能跑通,但页面要放在EAIMAR/dist/index.html这种子路径下,且oss.ymaikj.com已经绑给它了,你还得再绑一个dl.ymaikj.com。 收益不大,不推荐。
2. 开启静态网站托管
桶 → 数据管理 → 静态页面:
| 项 | 填 |
|---|---|
| 默认首页 | index.html |
| 默认 404 页 | index.html(可选,让任何路径都落到下载页) |
| 子目录首页 | 开启 |
不开这一项,访问 https://dl.ymaikj.com/ 会返回桶的 XML 列表或 403,而不是页面。
3. 绑定域名 dl.ymaikj.com
桶 → 传输管理 → 域名管理 → 绑定域名:
- 填
dl.ymaikj.com,勾选「自动添加 CNAME 记录」(域名在同一个阿里云账号下时可用; 否则去 DNS 那边手工加一条 CNAME 指向桶的外网 Endpoint) - ⚠️ 中国大陆地域的桶绑自定义域名,域名必须已备案。
ymaikj.com应该已备案, 确认一下子域名是否需要单独报备。 - 证书:同一页的「证书托管」里传一张
dl.ymaikj.com的证书。 阿里云「数字证书管理服务」可以申请免费的 DV 证书,签完直接在这里选。 不配证书 = 只能 http 访问,微信和现在的浏览器都会拦。
4. 上传页面与安装包
用 ossutil(推荐,能重复执行):
# 首次配置:ossutil config -e oss-cn-shanghai.aliyuncs.com -i <AK> -k <SK>
# 页面(放桶根)
ossutil cp deploy/dl/index.html oss://ymai-dl/index.html \
--meta "Content-Type:text/html; charset=utf-8#Cache-Control:no-cache, must-revalidate"
# 安装包
ossutil cp eaimar-release-1.0.2-20260923.apk \
oss://ymai-dl/android/EAIMAR/eaimar-release-1.0.2-20260923.apk \
--meta "Content-Type:application/vnd.android.package-archive#Content-Disposition:attachment"
也可以直接在 OSS 控制台点「上传文件」,然后在文件的「设置 HTTP 头」里改这两项。
⚠️ 页面必须设 Cache-Control: no-cache。默认缓存会让你改了页面之后老用户
还拿着旧版本,而这种问题根本没人会来报。
⚠️ APK 建议设 Content-Disposition: attachment。不设的话部分浏览器会尝试
「预览」这个文件,表现为点了没反应或者打开一堆乱码。
三、与管理后台联动(版本号、商店链接、更新日志)
页面打开时会调一次 POST https://ym.ymaikj.com/api/home/user_getchannelapps
(该接口在网关白名单里,未登录可调),把后台配的东西取回来:
| 页面上的 | 来自后台哪里 | 落到哪个字段 |
|---|---|---|
| 版本号 | 服务配置 → 版本与分发 → 发版配置 → 线上版本 | app_release.version |
| 「本次更新」 | 版本与分发 → 发版配置 → 更新日志 | app_release.changelog |
| App Store 链接 | 版本与分发 → 渠道分发 → 全球-苹果(101) 的下载地址 | channel_app.address |
| 各安卓商店链接 | 渠道分发 → 华为(1) / 小米(2) / OPPO(3) / VIVO(4) / 荣耀(5) | 同上 |
| APK 直链 | 渠道分发 → 官方渠道(100) 的下载地址 | 同上 |
后台改完,页面刷新即生效,不需要重新上传。
渠道地址留空时后端会自动回退到「发版配置」里的默认下载地址(AppRelease.DownloadAddress),
所以只想维护一套地址的话,只填那一处就够——填成 https://dl.ymaikj.com 即可兜住所有渠道。
⚠️ APK 直链约定挂在「官方渠道(100)」下。这是本页面单方面的约定,后台界面上没有任何提示,
所以要么按这个约定配,要么去改 index.template.html 里 CFG.channels 的映射。
⚠️ 接口打不通时(断网 / 网关挂了 / 跨域被拦)页面用 CFG.fallback 的兜底值渲染,不报错——
用户是来下载的,给他看一个报错页没有任何用。代价是兜底值会比后台旧,
所以别把 fallback 当配置入口去维护。
四、发版时要做什么
- 打包,产物名按仓库约定:
eaimar-release-<版本号>-<时间>.apk(不要留app-release.apk) - 传安装包 —— 两条路任选:
- 后台传(推荐):服务配置 → 版本与分发 → 「默认下载地址」旁边的 上传 APK 按钮。
传到分发桶的
android/<应用>/目录(按应用分目录,先选应用才能传),带进度条, 传完**自动写进「渠道分发 → 官方渠道(100)」**的下载地址,不动「默认下载地址」那一格。 - 手工传:
oss://ymai-dl/android/,见上文「二、4」
- 后台传(推荐):服务配置 → 版本与分发 → 「默认下载地址」旁边的 上传 APK 按钮。
传到分发桶的
- 到后台「版本与分发」改线上版本与更新日志(用「上传 APK」传的话,官方渠道地址已自动写好)
⚠️ 后台上传的前置:分发桶要配跨域(CORS)
浏览器是直传到 OSS(预签名 PUT 打的是 ymai-dl.oss-cn-shanghai.aliyuncs.com,
不是 dl.ymaikj.com),所以桶上必须有 CORS 规则,否则浏览器直接拦掉、
XHR 只报一句没有细节的「网络错误」。
OSS 控制台 → ymai-dl → 权限管理 → 跨域设置 → 创建规则:
| 项 | 填 |
|---|---|
| 来源 | https://console.ymaikj.comhttps://console-dev.ymaikj.com |
| 允许 Methods | PUT(顺带勾 GET、HEAD) |
| 允许 Headers | content-type(或 *) |
对照:主桶 ymaioss 早就配好了(所以产品固件上传一直能用),
2026-09-23 实测 ymai-dl 的预检返回 403,需要照着补一条。
页面本身不用动。只有改页面文案/样式,或者 App 图标换了,才需要:
cd deploy/dl && ./build.sh # 重新内联图标,生成 index.html
# 再把 index.html 传一次
五、页面行为
| 环境 | 行为 |
|---|---|
| iOS | 跳 App Store |
| Android(认出品牌) | 主按钮跳对应商店,副按钮给 APK 直链 |
| Android(认不出品牌) | 直接给 APK 直链 |
| 桌面浏览器 | 两个按钮都给,提示用手机打开 |
| 微信 / QQ 内置浏览器 | 一进页面就弹遮罩,引导「右上角 ··· → 在浏览器中打开」 |
⚠️ 微信那一层不是可选项。微信会拦截 apk 下载而且静默失败——点了什么都不发生, 用户只会认为这个页面坏了。所以是进页面就提示,而不是等他点了才说。
品牌判断的口径与 App 内 getAndroidStoreInfoByBrand 一致:判的是手机品牌,
不是从哪家商店下载的(国内五家共用一个包)。认不出就走 APK,这个兜底方向是安全的。
商店地址与 APK 地址相同时(后台该渠道没单独配、回退到了默认地址)只显示一个按钮—— 两个一模一样的按钮只会让人犹豫点哪个。
六、待办
首选是去后台「渠道分发」配(见上文「三」),配了就不用动代码。
index.template.html 里 CFG.fallback 的商店链接目前是占位地址
https://emai.ymaikj.com/1223,搜 TODO(store-links) 能定位,它只在接口打不通时才会被用到。
各商店上架后可以顺手更新:
| key | 从哪拿 |
|---|---|
appStore |
App Store Connect →「App 信息 → Apple ID」,一串纯数字,拼成 https://apps.apple.com/cn/app/id<数字> |
huawei / honor |
各自开发者后台的应用详情页链接,形如 https://appgallery.huawei.com/app/C<数字> |
xiaomi |
https://app.mi.com/details?id=com.yimai.eaimar |
oppo / vivo |
各自开发者后台的详情页链接 |
⚠️ 包名是 com.yimai.eaimar(iOS bundle id 同名)。
七、注意
- 别在这个页面做 Universal Link 唤起:UL 域名是
yimai.games,不是ymaikj.com, 在 ymaikj 的任何子域上配都不会生效。 - 桶是公共读,APK 谁都能下——这对安装包是对的。但别把别的东西往这个桶里放。
- 下载量上来之后再在 OSS 前面挂 CDN,页面不用改(域名不变)。
- 图标在页面里只内联一份(
<img>),favicon 与 apple-touch-icon 由 JS 复用同一个 data URI。在<head>里再写两个 href 会把几十 KB 的 base64 存三份,页面体积直接翻三倍。