车间 App 的第一代形态不是原生开发,而是一个”壳”:原生 Android 工程里放一个加强版 WebView,加载 MES 的 H5 页面——业务全部在 Web,壳只负责把网页够不到的原生能力(扫码、推送、PDF、拨号)以桥接口的形式递进去。这个形态常被诟病”不就是套壳吗”,但维护过它的人知道:**壳的难点不在写,在”老”**——一个 minSdk 19 时代的壳,要在 targetSdk 34 的新规下继续活着,每一轮安卓版本升级都是一场适配战役。
本篇拆这套 X5 WebView 壳(交付篇工控终端的手机版兄弟):JSBridge 的设计、扫码的双通道降级、推送如何路由回页面、Cookie 会话的同步,以及老壳适配新系统的踩坑实录。下一篇的鸿蒙移植版会和它形成直接对照——同一套 Web、同一个桥接口约定,换一个操作系统重新长出来。
一、为什么是壳:H5 的一票优势和一票否决
先讲选型账。MES 的移动端需求是报工、质检、查询——表单加列表的形态,H5 的开发效率碾压原生(一套代码 PC 移动通吃,改版免发版);但有两个能力 H5 永远做不好:扫码(车间需要连续扫、快速扫、离线扫,浏览器相机权限和性能都不行)和推送(消息要到达杀掉的后台)。壳的定位由此确定:H5 承担业务,原生只补两个一票否决项,外加若干便利项(PDF 渲染、拨号、清缓存)。
WebView 选了腾讯 X5 内核而不是系统 WebView——理由是那个年代安卓厂商的碎片化:系统 WebView 版本随厂商 ROM 参差不齐,X5 把内核统一(还能共享内核进程),扫码、文件上传这些能力在低端机上的表现可预期。代价是包体和一套 X5 自己的初始化生命周期,以及”X5 加载失败怎么办”的问题——壳里做了系统内核兜底:X5 初始化失败就退回原生 WebView,功能降级但可用。内核可选、桥不可选,这是壳设计的优先级。
二、JSBridge:十五个方法的能力清单
壳向 H5 注入一个桥对象(WebView 的 addJavascriptInterface),网页侧全局可调。方法清单是这个壳的需求史化石,按职能分四类:
- 扫码族:单次扫码、连续扫码(扫码枪式的连续识别,每枪一个回调直接回 H5)——报工场景扫料箱码是高频动作,连续模式省掉每次点按钮的开销;
- 推送族:绑定推送账号(用户登录后把推送 token 和账号绑定)、解绑、点击通知跳转指定 MES 页面;
- 文档族:打开 PDF(原生渲染组件翻页,H5 渲染大 PDF 在老机器上会卡死)、拨号;
- 运维族:清缓存、多语言切换、获取版本号。
JSBridge 的通信语义是”单向调用加钩子回传”:H5 调原生方法,异步结果通过壳反向执行 H5 的全局约定函数回来(扫码结果调 barCodeReturn、推送点击调 turnToPage)。和上一终端篇工控壳的”属性共享加反向钩子”如出一辙——两家壳团队隔着两三年和两门语言,独立收敛到了同一个桥模型,这本身就是这个模型适配”Web 加薄壳”形态的证据:异步原生能力和无状态 H5 之间,钩子是最不容易出错的回传方式。
桥的安全清单也值得一列:addJavascriptInterface 在老安卓上有著名的漏洞(注入对象可反射调系统 API),minSdk 19 之上系统已修复,但桥方法仍然按最小暴露原则设计——没有任何文件读写、反射、动态加载类的方法;HTTPS 混合内容按页面域白名单放行。
三、扫码的双通道降级
扫码值得单独一节,因为它是车间 App 的命根子。方案是双通道:自研封装的 ZXing 通道(开源解码库,纯 Java,什么机器都能跑)加华为 HMS ScanKit 通道(厂商级识别算法,快、抗污损能力强)。策略是优先走 HMS(华为系设备识别率和速度明显更好),不可用或失败降级 ZXing——降级不是异常处理,是常态路径,因为车间设备的品牌分布就是混杂的。
连续扫码模式是工业场景的特有需求:仓储员拿着扫码枪式操作,一秒一枪,每枪立即回传 H5 处理、自动进入下一枪。实现上要把解码线程和相机预览的生命周期管理做稳(连扫模式下的对焦风暴和内存抖动是两大杀手),壳里为此有一套专门的解码封装包。
四、会话与推送:两个”跨世界”的数据流
Cookie 同步:MES 的登录态是 Session Cookie(登录会话篇),H5 在 WebView 里登录后,Cookie 存在 WebView 的 CookieManager 里——但推送、更新检查这些原生发起的请求不经过 WebView,它们要自己带会话。壳的方案是 Cookie 同步:WebView 的 CookieManager 和原生 HTTP 客户端的 Cookie 上下文做一次同步桥接,让两类请求共享同一份登录态。这个细节的坑在于 Android 两套 Cookie API 的时代差异,老壳里的同步代码就是一部 API 变迁史。
推送路由:推送到达时的行为链是”原生接收 → 解析扩展字段里的目标页面 → 拉起 App → 命中 H5 后反向调 turnToPage 把路由交给 H5”。注意路由决策在 H5 手里——原生只知道”目标页面标识”,具体跳到 H5 的哪个路由由前端映射。和工控终端的”执行与决策分离”同构:原生壳不做业务路由决策。
热更新:壳自身的更新走第三方更新库检查版本、下载 APK 安装——但注意壳的版本节奏极慢(一年一两次),真正的”热更新”是 H5 层的:Web 改完发布即生效,壳根本不用动。壳的版本号和业务的版本号是两条时间线,这是壳架构能活七年的根本原因。
五、老壳适配新系统:一部对抗史
这一节是本篇最值钱的部分:minSdk 19(Android 4.4 时代)的壳活到 targetSdk 34(Android 14),中间隔着十年安卓权限与隐私新规,每一轮 targetSdk 提升都是一次适配战役:
- 运行时权限:相机、存储从安装时授权改为运行时动态申请——扫码是核心功能,权限拒绝的降级体验(提示去设置开启)要专门设计;
- FileProvider:安卓 7 之后应用间共享文件(下载的 APK、PDF)不能再裸传 file:// 路径,要配 FileProvider 走 content://——更新安装和 PDF 查看双双中招;
- 后台限制:推送进程保活被一代代收紧,最终方案是接受现实——推送靠厂商通道(壳里集成的推送 SDK 的厂商通道族)到达,而不是硬保活;
- 包可见性:安卓 11 起查询其他应用要声明 queries,版本更新检测”看不见安装包”的坑由此而来;
- 混合内容:WebView 默认不放行 HTTPS 页面里的 HTTP 资源,MES 的老图片域名是 HTTP 的,混合内容模式按域名评估后放行——安全和现实之间的又一次讨价还价。
老壳维护的元认知可以压成一句:壳的代码量十年几乎没涨,但适配代码的占比从一成涨到了一半——“让老东西活在新时代”的工程量,全在看不见的地方。
六、面试视角:六个问题拆到底
Q1:为什么移动端选 H5 壳而不是原生?
答:需求形态决定的。报工质检是表单加列表,H5 的跨端一致性和免发版碾压原生;真正必须原生的只有扫码和推送两个能力,为它们全量原生不划算。壳的架构把”原生能力清单”控制在最小集,换来业务层七年免发版。代价也认:WebView 的体验天花板(低端机的滚动、输入)是壳形态的宿命。
Q2:JSBridge 的回传为什么用钩子不用 Promise?
答:历史加稳健。壳的第一版就定了”单向调用加全局钩子回传”,H5 侧的调用方覆盖多个团队,钩子模型对调用方要求最低(不用关心原生侧的版本支持 Promise 化改造)。另外连续扫码这类高频回调,钩子加事件流比逐次 Promise 更贴合。新桥如果要重新设计,我会加一层 Promise 化封装,但保留钩子作底层——兼容存量调用方。
Q3:扫码方案为什么做双通道?
答:车间设备品牌混杂,HMS ScanKit 在华为系设备上识别率和速度明显占优,但非华为设备装不上或不好使;ZXing 纯软件实现全设备可跑但慢。双通道优先 HMS、降级 ZXing,把”识别率”和”可用性”两个目标分开满足。工业扫码还有连续模式的特殊要求(高频回调、对焦管理、内存控制),这是和消费级扫码最大的差异点。
Q4:推送怎么保证到达和路由正确?
答:到达靠厂商通道而不是保活——安卓后台限制一代代收紧,硬保活是与系统对抗,长远的路只有厂商通道。路由是”原生只递目标标识、H5 决定跳哪”的分工:原生不认识业务路由,H5 收到标识自己映射。点击通知时 App 可能是冷启动,冷启动和热启动的两条路由时序要分别处理——这是推送路由最容易漏的分支。
Q5:WebView 的登录态和原生请求怎么共享?
答:Cookie 同步桥:H5 登录后 WebView CookieManager 里的会话 Cookie 同步给原生 HTTP 客户端,推送绑定、版本检查这类原生请求就能带同一份登录态。坑在两套 Cookie API 的版本差异和同步时机(登录跳转完成后再同步)。原生侧坚持不存用户名密码,会话的权威来源始终是 Web 登录。
Q6:维护一个 minSdk 19 的老壳是什么体验?
答:代码量十年不涨、适配代码占比涨到一半的体验。每次 targetSdk 提升都是一轮战役:运行时权限、FileProvider、后台限制、包可见性、混合内容——每一项单看都小,加起来是持续的税。元认知两条:壳要尽量”哑”(能力少、逻辑少,适配面才小);能用 Web 解决的绝不进壳(壳里多一行代码,就是十年适配税多一行税基)。
小结
- 壳的定位是补一票否决项:扫码和推送原生做,业务全留 H5——原生能力清单最小化是壳能活十年的根因;
- X5 内核换统一性,留系统内核做降级:内核可选,桥不可选;
- JSBridge 是单向调用加钩子回传:最小暴露原则加连续扫码的流式回调,两个壳团队隔语言隔年份收敛到同一模型;
- 扫码双通道是常态路径不是异常处理:HMS 优先 ZXing 兜底,连续模式是工业场景的特有需求;
- 推送靠厂商通道不硬保活,路由决策留给 H5:原生不做业务决策,冷热启动两条时序分别处理;
- 老壳的十年是适配税的十年:权限、FileProvider、后台限制、包可见性——壳要”哑”才配活得久。
下一篇预告:HarmonyOS NEXT 从 0 到 1——同一个车间 App 在鸿蒙上的重新长出:ArkTS 与 Stage 模型的全新世界观、ArkWeb 壳复用同一个桥接口名让 Web 零改动、签名上架流程,以及一个 Android 老兵写 ArkTS 的观念转换清单。