4.3 KiB
zcbot 移动 App 套壳对接
给 platform 工程:把 zcbot 控制台打包成移动 App。 架构:原生壳(WebView)+ 原生登录页。登录调 platform 自家接口换出 zcbot JWT,WebView 加载 zcbot 控制台时把 token 放 URL fragment 带入;token 失效时 zcbot 跳回
relogin_url,原生壳拦截后静默换新 token 重进。zcbot 前端不打包进 App,前端迭代不发版。
1. 登录链路(platform 自有接口,2026-07-21 实测可用)
GET /api/login/check_captcha_required/<username> → {require_captcha: bool}
GET /api/login/captcha?key=<随机串> → 验证码图(仅 require_captcha 时)
POST /api/login/token → platform access_token
form: username, password, key(必填,即使无验证码), grant_type=password [, captcha_text]
POST /api/login/external-login → zcbot JWT
header: Authorization: Bearer <access_token>
external-login 返回的 data 字段:
{"token":"<zcbot JWT>", "user_id":"<uuid>", "name":"...", "user_name":"...",
"expires_at":"...", "ttl_seconds":604800}
其中 token / user_id 就是下一步进入 zcbot 所需的全部。
2. zcbot 进入契约
拿到 JWT 后,WebView 加载:
https://<zcbot 域名>/static/dev.html?embed=1&relogin_url=<回登录入口的地址>#token=<JWT>&user_id=<UUID>
- fragment:
token/user_id两个字段都必填;zcbot 读完立即清掉,不留在地址栏和历史。 relogin_url:必须是带 scheme 的绝对地址。原生壳推荐自定义 scheme(如zcbotapp://relogin);javascript:等可执行 scheme 会被拒。- 401 行为:zcbot JWT 失效时页面
location.replace(relogin_url)。原生壳在shouldOverrideUrlLoading(Android)/WKNavigationDelegate(iOS)拦截该跳转 → 用缓存的 platform token 重调external-login→ 带新 fragment 重新 loadUrl。 - token 生命周期:zcbot JWT 7 天 TTL + 滑动续签(活跃期间自动续,页面内已处理)。App 每次冷启动都换一张新 JWT,实际只有 platform token 过期(约 30 天)才需要用户重输密码。
- 可选
&task_id=<uuid>:进入后自动定位到该 task。
冷启动静默登录:壳启动 → Keystore/Keychain 里有 platform token → 后台调 external-login → 直接 loadUrl 进控制台,用户无感;没有或已失效 → 显示原生登录页。
3. 原生壳杂活清单
| 项 | Android | iOS |
|---|---|---|
| 文件上传 | WebChromeClient.onShowFileChooser |
自带 |
| 文件下载 | DownloadListener → DownloadManager |
WKDownloadDelegate(iOS 14.5+) |
| 返回键 | canGoBack() ? goBack() : 退出确认 |
手势自带 |
| DOM storage | setDomStorageEnabled(true)(必须) |
自带 |
| 键盘顶起 | windowSoftInputMode="adjustResize" |
自带 |
| 外链 | 非 platform/zcbot 域交给系统浏览器 | 同左 |
| PDF/PPT/HTML 预览 | zcbot 前端内置渲染,无需原生 PDF 组件 | 同左 |
SSE 流式输出两端 WebView 原生支持,无需处理。iOS 上架提醒:纯套壳有 App Store 4.2(最小功能)被拒风险;企业分发 / TestFlight / 仅 Android 无此问题。
URL 白名单只处理主 frame导航。Android 检查 request.isForMainFrame,iOS 检查 navigationAction.targetFrame?.isMainFrame;不要拦截 zcbot 页面内部的 worker 或子 frame 请求,否则 PDF.js worker、HTML sandbox 等站内预览仍会白屏。
4. 备选:H5 登录页
不想写原生登录 UI 的话,可在 platform 域上放一个 app.html(登录表单 + 调自家接口,同源无 CORS),换到 JWT 后 location.replace 按 §2 契约跳进 zcbot,relogin_url 填 app.html 自己的地址(401 跳回来时若 platform token 还在缓存,静默重签再跳回,用户无感)。契约完全相同,只是登录层从原生换成网页。
5. 安全要点
PLATFORM_KEY只在 platform 后端(external-login内部用),App / 前端代码里绝不出现。- 不存明文账密。"记住登录"= 把 platform token 存 Keystore / Keychain,靠 token 生命周期免登,不缓存密码重放。
- 建议 platform 侧修:
POST /api/login/token响应的user对象把hashed_password原样下发了,应在序列化时剔除。 - WebView 域名白名单:只放行 platform 与 zcbot 两个域 + 自定义 scheme,其余交系统浏览器。