做 App + H5 混合应用的请进,想听听看看

2022-11-24 20:03:57 +08:00
 karott7
公司是做 app 的,然后有些复杂的或者活动页面会用 H5 做,然后嵌套在 app 里。
想知道有多少人选择离线包方案,相比于打开 webview 加载 H5 使用 HTTP 缓存策略,你们觉得哪种方案更好?

- 离线包方案:将整个 H5 资源包打包到服务器,启动 app 进入首页时空闲期间下载离线包
- webview + http 缓存方案就不解释了
3194 次点击
所在节点    程序员
33 条回复
kop1989smurf
2022-11-25 00:21:06 +08:00
@karott7 #20 如果要不是“必须二选一”这种话题的话,我同意你此楼的看法。
确实在基建很完备的中国,很大程度上,单纯离线 html 的 hybrid app 意义不大。(尤其楼主这种离线 html 生命周期只有一次 launcher 的情况下,其实是并没有发挥离线 html 真正的优势)

所以相对而言,二者兼而有之,不同的页面根据业务需求用不同的缓存逻辑,是一个更加合理的方案。
但其实这也有弊端,比如会导致跳转逻辑复杂度变高,缓存逻辑复杂等等。
这就要看楼主根据 app 的业务来取舍了。

欢迎楼主继续交流。
SolidZORO
2022-11-25 00:49:52 +08:00
sw + 自己实现一套刷新 sw 的机制。

两年的最佳实践。
RightHand
2022-11-25 07:30:35 +08:00
@karott7 你这是两个问题,用了 webview 就别说性能问题了。你应该想要解决的的弱网环境首次加载的问题,如果细说 h5 的及时加载其实是 html 中的多媒体文件加载速度。另外缓存的方案一定讲得是命中率,全量缓存是命中率高了,但对用户及不友好。你说的那些场景也不过是优化这个命中率而已。再说增量缓存控制的问题,首先是命中率问题。再着肯定是原生来控制缓存更灵活,那么既然都原生控制了为什么不用原生来实现呢,原生配合 js 调度的问题复杂度太高了( Web 前端大佬我见过不少,app 大佬更不少,但是同时都懂的大佬基本见过)。所以目前的方案基本都是尽量取双方优点。如果一个样式,效果,逻辑能撑一个版本发布那就原生实现,不能则考虑 h5 实现(无缓存或只缓存多媒体信息)
zpxshl
2022-11-25 08:39:40 +08:00
用了 xxx 就别在意性能了...真是二极管的思维啊。
woxihejinghao
2022-11-25 09:06:23 +08:00
离线包,web 加载完成后性能还可以啊。但是做这个要做好版本管理,下载新的清理旧的,MD5 校验,验证资源的可靠性。
RightHand
2022-11-25 09:17:21 +08:00
@zpxshl 求大佬出个全平台且性能比肩原生的框架,既要 又要
kamilic
2022-11-25 09:59:22 +08:00
@karott7 你说得很对,我们公司也做过,我自己的结论也是跟你差不多。
我们公司比较多单页面应用,html / js / css 加载基本不需要时间,FCP 快了不少。
对于页面需要请求接口的项目,接口响应速度慢的话一样的慢,LCP / FMP 还是慢,这种离线包方案只能在那些相对静态的页面中起到「秒开」的效果。

总结起来,我更喜欢爱奇艺那边的那套 service-worker 机制,前端自己可以控制缓存逻辑。
https://zhuanlan.zhihu.com/p/148931732

其他离线包的方案,横竖看都觉得是对 service-worker 的拙劣模仿 🤣
Mather
2022-11-25 12:11:39 +08:00
利益相关,暂不能透露具体是哪款 APP 。

先说说背景:
项目因为原生实现某种功能难度较大,加上投入、历史遗留等其他因素限制,选择了“App + H5 ”混合应用的混合式方案对 APP 中的业务实现进行改造升级。改造项目进行时,对这个主题做了思考。

项目经过两年的几次迭代,分别试过楼主所说的两种方案:
• “webview + http 缓存”
• “离线包”

上面两种方案,我们在日活跃 5k 左右的项目上实验了两年左右。
最后因为“内容可控”和要“快速修改”的要求,和面对“网络劫持”的问题,选择了“离线包”方案。

---------------------------------------------

在项目完成后,我对方案做了技术总结,分析了它们的优劣:

• 在线服务,“webview + http 缓存” 方案

项目研发时,我们不约而同地想到在线服务的加载形式,即客户端使用域名的形式访问提供加载资源的 HTTP 服务器。

在线服务与 Web 应用程序别无二致,使得我们有更多的时间投入到设计应用生命周期和程序 API 中去。

可是随着项目上线若干个月,在线服务存在的缺陷便暴露出来:

- 没有预加载:首次打开的体验很差,所有文件都要从网络请求
- 缓存不可控:缓存的大小和策略由系统 webview 控制。缓存的清理逻辑不可控,往往加-载缓存几张图片后,重要的 HTML/JS/CSS 缓存就被清除了
- 网络劫持:页面被运营商或其他第三方劫持,将长时间缓存劫持的页面,导致整个功能失效

• 离线加载,楼主的“离线包”方案

离线加载方式能较好的解决在线服务存在的若干问题。

离线加载方式把功能模块的页面和资源打包在客户端中,Webview 组件加载本地资源文件,避免了联网因素的产生。 亦可将页面文件压缩成离线包,在自定义时机把离线包下载下来,做解压、校验等工作,达到在线更新 /热更新的效果。

- 离线包:前端项目构建产出的文件打包成 zip 格式,并以 ${project}_${date}_${verison}.zip 命名方式交付至客户端,存放在 App 项目内作为资源引用,称为离线包。

- 下载包:与离线包的产出相似,下载包定义为某个离线包的迭代版本,文件将存放于服务器或 CDN 上,便于客户端需要时下载。

---------------------------------------------

总的来说选哪个方案,考虑方案的优劣,最终要从投入产出比来考虑,以及面向立项中主要问题出发,才能解决实际问题。
从生产中解放出来,陪陪你爱的人,做些美好的事情。
Mather
2022-11-25 12:57:37 +08:00
@july1995
Android 的 webview 实现,使用腾讯浏览服务( X5 内核),有专门的 TBS Studio 工具能帮助开发者分析和优化网页的设计,主要功能有网页 Inspector 调试,网页性能分析等。

iOS 端在打包 APP 时候,开启调试模式,使用 Mac Safari 进行联机调试,具体可百度搜索“safari 调试 webview”。

--------------------------

参考资料
腾讯浏览服务: https://x5.tencent.com/
TBS Studio: https://x5.tencent.com/tbs/guide/debug/season1.html
zpxshl
2022-11-25 17:48:23 +08:00
@RightHand webview 性能是比原生差,不代表用 webview 实现的就完全不注重性能。 都是综合考虑各种取舍的。
按你的逻辑,使用非原生方案的就没必要提性能问题了,再差都得接受吗。
别的不说,站在用户体验上看,用 h5 实现的业务,离线包能大幅度减少首次打开的时间。 至于为啥要用 h5 ,自然有别的考虑。 在意性能不代表性能就是绝对第一优先级。

我们之前就做过类似的混合开发。 部分页面用 webview 实现的原因是:那些业务用原生实现的话人力成本极大。 远高于 1:2 。 至于你说的同时懂原生和 js 的人是不多,但这并不是大问题。 两个团队的人分别负责维护原生和 js 就行了。
karott7
2022-11-25 22:05:24 +08:00
今天工作忙,所以只能晚上来回复了;也感谢楼上几位朋友的分享,我也有一些新的收获。

--------------
先说下我为什么不太能接受离线包方案
1. 正常情况下 SPA 应用多数页面都是要和服务端交互的,你有页面不能走通接口有啥意义
2. 离线包我公司要前端 /后端 /客户端三人合作,前端还有控制版本,人力成本高;至于离线包增量更新,这不是重新实现 http 缓存方案吗?放着现有的 http 缓存机制不用,自己花时间去做,不浪费时间?站在开发者角度,我觉得不够有效率
3. 站在用户角度,你能接受你手机的 app 下载在 H5 更新后就直接下载一个可能几兆的离线包,甚至很多页面你都不会访问。

我如何解决部分白屏时间的 (我用 react ):
1. H5 加载流程是这样:webview 启动( A )-> 请求 index.html 并解析( B ) -> 请求主要模块和首页资源( C ) -> 进入首页( D );
可能造成页面白屏的阶段是 A 、B 、C ,A 阶段到 B 阶段( dom 和 css 解析完成之前)需要客户端处理(加个 loading ?),B 阶段 ( dom 和 css 解析完成之后)就会展示 <div id="root"></div>,这里开始到 C 阶段又是一段比较久的白屏,因为主要模块一般比较大(几十到两三百 kb );
- A 阶段我就不说了,不是前端能处理的
- B 阶段到 D 阶段之前是可以处理的,其实 <div id="root"></div> 可以改为 <div id="root"><span class="loading" /></div> 的,dom 和 css 解析完到 react 模块加载完成是就会展示这个 loading 样式(用 style 会比 svg 动画好);然后主要模块体积也要小,引入外部模块也要考虑模块体积。打包后的首屏体积一般 500kb 以下,控制到 100kb 也不是没可能
- D 阶段进入首页之后就用 import 方法预加载其他页面或者模块资源。( service worker 我没研究,就不说了

2. 说说 http 缓存
- 服务器会默认给 html 、css 、js 、img 等资源设置一个 3600s 的缓存有效期。假设你什么都不做,你更新内容发布上线,会有页面没更新的情况,因为 html 这个文件是有缓存期的;需要对这个入口文件设置 no-cache (感谢 @lisongeee 提醒协商缓存) 或者 no-store 缓存响应头,就能保证每次进来都是最新的;其他资源都设置一年缓存过期时间,这样对用户体验就很好了,只要用户访问过该资源,设备就会缓存资源到本地,二次进入就是秒开。

我觉得对于 SPA 应用,即使是弱网环境,客户端在获取 html 之前设置 loading 展示 + 前端加载主要模块设置 loading + http 缓存

------
@kop1989smurf 你说的首屏广告这都属于特殊情况,还有类似笔记应用等多数页面不用和服务端交互的我觉得用离线包没问题,但是用户上面的解决白屏的方法+控制首屏资源体积+http 缓存真的适用于大多数场景。

或许 app 加载后可以在后台开个 webview 预加载 H5 首页,之后再访问 H5 主要模块不就走缓存了么?
karott7
2022-11-25 22:08:11 +08:00
@kamilic 感谢提供方案,等我有空也研究下 service worker
karott7
2022-11-25 22:12:32 +08:00
@woxihejinghao 离线包加载完成后肯定行啊,重要的是人力成本;你说的更新这些,http 缓存机制都有,除去 cache-control 相关的相应头还有 Last-Modified ,etag

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/897674

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX