阶段1 - 发现问题
1. 收到用户反馈,IPad离线情况下某些不能正常显示
- 试图在电脑上复现此问题,但是没有成功
- 在Ipad上复现问题,也没有成功
- 与PA沟通确认问题
问题只发生在IPad 系统版本15.x的设备上,且加载应用为桌面应用(此应用区分桌面端和手机端)
2. debug问题
- 成功复现问题
- 发现现象
- 安装时候看不到应用图篇
- 安装之后service worker 状态正常
- 图标文件请求失败
- svg 图标请求失败
- 首次打开白屏
3. 分解问题,分步修复
3.1 安装找不到应用图标
- 查询图片支持情况变化
所以,从上面的信息看上去,link标签优先级最高,永远起作用!(坑)
但是,之前的代码里面是有指定图标的。
怀疑 1 尺寸不合适?
所以更新尺寸为144x144 参照于Angular.io
测试之后发现并不起作用
怀疑 2 难道是144尺寸不合适?
那我就给一个全尺寸!
于是,加上了所有尺寸的设置。但是结果仍然是不起作用。
由此可知,方向不正确,但是正确的方向在哪里?
- 试图在本地复现问题
监狱应用程序存在权限校验所以,所以打算测试基本的happy path. 注释掉了所有的UI,只保留了入口页面。编译,启动本地服务器。使用IPad打开本地应用,可以看到图标,安装正常。
这里证明了入口文件的图标设置是没有问题的, 至少修改之后的图标设置是正确的
怀疑 3 问题产生在代码内部?
查看近期的修改历史,发现了入口修改新增加了 APP_INITIALIZER。
怀疑这段代码的原因是,Service Worker 的注册发生在软件初始化的时候,而这里的修改影响了初始化。
所以,我注销了这部分代码,本地启用Proxy试图验证猜测。结果发现,一切正常。
难道这就是问题的原因?
为了验证这个猜测,把测试代码推到测试服务器。使用线上测试环境来验证问题。
结果是,然并卵。
但是,监狱之前认定问题出在代码内部,所以
猜测 4 是不是最近新增的
Guard有关系? (这里其实方向已经错了)
所以注释了Guard相关的代码,推到线上测试环境进行验证。
结果还是,然并卵。
此处暂时迷失方向
偶然发现的转机
在使用MacBook debug 的时候,发现Safari自带的Dev Tool是真的不好用。service worker 的请求基本上看不到。所以试图借助第三方工具来抓包。
但是公司的电脑和网络对数据包都进行了二次加密,完全看不到任何有用的信息。
所以,晚上回家使用自己的电脑和网络进行抓包。这时候发现了问题的根源。
Safari 向服务器发送了错误的User Agent
先简单介绍一下我们应用的工作流程:
前端的请求都会经过Router来做判断,判断的依据就是User Agent.是手机的User Agent 会将请求转发到手机对应的后端,是桌面端请求的会转发到桌面端对应的后端。
问题就出在Router这里,桌面端的Manifest图标在经过Service Worker请求的时候发送的User Agent不正确,请求被转发到了错误的后端,造成资源请求不到。
Service Wroker 请求Manifest图片携带的User Agent:
Service Worker 请求其他资源时携带的User Agent:
所以,修改了Router部分对User Agent 处理的代码之后,图标问题就被解决了。讲道理这是Safari的Service Worker部分的BUG。
- svg文件缓存失败问题
这两个问题其实是一个问题,就是在写路径的时候加了一个斜线。
原本这样写是没有问题的,Assets确实在根路径下。但是,后来修改了项目的部署路径。
手机端部署在 Https://domain/mobile/XXXXX
电脑端部署在 Https://domain/desktop/XXXXX
所以对应的资源就不在根路径下了。
- svg icon 不能正确显示问题
我们使用的部分svg 图标是下面的写法,这种写法在加载的时候会请求svg文件名#id
但是这个请求Service Worker其实并没有缓存,所以会在离线的时候还试图发送请求。
上面的修改依赖把svg template 定义到root html 内部才能这样写。 而且这里是自定义的table cell 所以不支持mat-icon。
- 打开之后白屏问题
原因一:推测
从Safari 浏览器添加到桌面之后,直接打开桌面图标。这时候Safari 浏览器的页面和Service Worker 工作中。并且新起程序会认为Service Worker 已经启动,新页面资源加载会排在所有缓存资源的队尾执行。
这就是为什么有时候经过长时间等待之后会看到页面被加载。
原因二:
打开新图标之后,Safari从当前域下不能获取SID(token),由于没有 sid 这时候会跳转到登陆服务器。但是这时候Service Worker是正在工作的。所以,原本的域名跳转会被Service Worker来fetch,这时候就会报错,页面就死在当前状态。
原因三:推测
这种情况是类似于原因一,有时候即使经过长时间的等待,页面依然白屏。dev tool能看到的请求也只有页面的请求和极少数的几个资源请求,但是都没有执行。怀疑是Service Worker 一直pending在一些请求上。但是这些请求实际上已经完成了。
所以,针对这个问题,目前的办法就是在安装应用之后,主动杀掉浏览器的页面。然后再打开应用。
补充: Chrome 和 Safari 针对PWA安装之后的标签页的处理逻辑不一样。 Chrome 会完全复用浏览器已经加载的所有资源和Service Worker. Safari 会认为是一个新的物理层,会重新缓存所有的资源。对于Service Worker我个人理解是也没有复用。 安装应用启动的时候,由于当前域的一致,导致的冲突造成的属于自己的Service Worker没有起来。我这么认为的依据是浏览器内Service Worker缓存的资源,安装应用的Service Worker一样要缓存一遍。
总结
此问题其实并不具备代表性,只是我们在PWA商用化上的一些特殊情况。
不过实话是说,Mac在这方面是有些坑的。就像User Agent 这种问题,Safari 自己的dev tool根本抓不到。
如有错误,欢迎指正。