PWA以及Hybrid开发方案简介
PWA
PWA(Progressive Web App)渐进增强的Web App。最早提出在2015年,它最初的设计理念是,保留Web的精髓,让Web逐渐演进成App,而非现在Hybrid App(即现在最常用的UIWebView/WebView+前端)形式。
- 可安装性
- 离线能力
- 推送能力
在PWA的概念下,网页可以被添加到主屏同时支持全屏运行,在Service Worker帮助下可以离线运行,最后它仍是Web而并不用添加到App Store中。
说到Service Worker很多人可能会想到Web Worker的概念。这两个看起来是包含关系的概念实际上有区别。
- Web Worker是JS多线程的一种实现方式,借助它可以让脚本在后台运行,worker对象和主线程通过message的方式交流,caniuse上的支持度为93%
- Service Worker是浏览器的一个新特性,配合PWA的概念一起使用,是PWA网络请求的代理,结合缓存管理等方案,提供很好的离线体验,caniuse支持度仅有73%
一个介绍ppt上展示了具体的区别:
- 和tab的关系,Web Worker是一tab对多Web Worker,Service Worker则是多对一
- 生命周期,Web Worker和选项卡同生共死,Service Worker则是完全独立的
- 擅长场景,Web Worker用在多线程协同,Service Worker则可以提供很好的离线体验
- 为保证安全Service Worker要求scheme为https
Service Worker通过navigator.serviceWorker.register('path').then
的方式注册,之后便能通过监听事件拿到所有scope里发生的请求,当然,可以在path后的第二个参数中显式地声明作用域(如{scope: '/js'}
)。Service Worker可以监听它声明周期中的各事件
- Install 发生在第一次注册和sw.js(这里的文件名只是举个例子)改变时,通常在这个阶段设定SW的初始状态和准备好缓存。缓存可以借助caches API完成。
- Fetch 发生在网络请求产生时,任何匹配了Request的网络请求都会被拦截,并返回缓存数据。只有找不到存在的缓存,才会产生一个请求
- Activate 发生在SW更新或网页关掉再重新打开时,触发在install之后
- Sync 发生在用户有网络时,用在用户进行依赖网络的操作时,会推迟到有网络时再执行。简单来说,所有的依赖网络的操作,都需要使用sync事件
除了Service Worker,Manifest也是很重要的一部分。它用来描述应用程序的各种信息。它包括下面一些成员
- background-color 在css加载前用作应用背景颜色
- name 应用名,short_name也是类似意思
- description 应用描述
- display 显示模式,有
fullscreen
,standalone
,minimal-ui
和browser
几种可以选择 - icons 应用图标,数组类型,每项包含
src
,type
和sizes
几个属性 - orientation 默认的屏幕朝向
这里有一个收集PWA酷站的地方。
Hybrid方案相关
离线包管理方案:
- 本地开发测试,提交特性分支到远端,
- 通过提MR的方式合并在当前迭代分支上,触发basement自动CI为zip格式,根据当前发包的状态,传递给NebulaMng管理
- NebulaMng基于zip生成版本号和配置文件,构建整个离线包,并推送给应用中心
- 应用中心负责向客户端推送更新
- 客户端根据策略拉取离线包、解压、渲染
离线包本地渲染方案:
- 加载公共资源包
- 判断本地是否已安装该离线包,若有,则加载到内存,否则触发离线包下载
- WebView加载离线包url链接,加载前检查内存中是否存在页面数据,若有,从内存中取出并渲染,否则fallback到线上cdn地址
离线包更新方案:
- 应用中心广播或服务端发sync消息触发
- 向wapcenter获取当前客户端下所有包信息
- 在本地没有当前版本且WiFi条件或auto_install为1时更新本地包
双向通信和JSBridge原理:
- WebView在载入页面时,注入JSBridge脚本。通过调用JSBridge.call,触发调用参数的序列化,并调用
console.log(h5container.message:xxx)
或window.prompt
事件。WebView监听页面的console或prompt事件,解析传递的参数信息,然后通过NebulaService分发事件 - Service、Session、Page实例化时,内部都有一个H5PluginManager成员,通过类似EventEmitter的形式存储着一个action -> plugin的map。每个plugin都有interceptEvent和handleEvent两个函数,处理事件的拦截和处理两个阶段
- WebView通过loadUrl(“javascript:JsBridge.callback”)的形式输入结果并运行回调
实现上类似这样:
1 | ;//JsBridge |
native和H5混合方案:
- 在RootView中创建离线包View再异步添加进来
- 通过JSBridge进行交互
- 提前拦截touch事件,防止冲突