zcbot/APP.md

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 自带
文件下载 DownloadListenerDownloadManager 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_urlapp.html 自己的地址(401 跳回来时若 platform token 还在缓存,静默重签再跳回,用户无感)。契约完全相同,只是登录层从原生换成网页。


5. 安全要点

  1. PLATFORM_KEY 只在 platform 后端(external-login 内部用),App / 前端代码里绝不出现。
  2. 不存明文账密。"记住登录"= 把 platform token 存 Keystore / Keychain,靠 token 生命周期免登,不缓存密码重放。
  3. 建议 platform 侧修:POST /api/login/token 响应的 user 对象把 hashed_password 原样下发了,应在序列化时剔除。
  4. WebView 域名白名单:只放行 platform 与 zcbot 两个域 + 自定义 scheme,其余交系统浏览器。