iOS 端容器之 WKWebView 那些事( 五 )


2)造成WKWebViewCookie问题的根本原因App进程与Networking双进程的设计 。
核心目标
在了解WKWebView问题以及对应的根本原因之后 , 如何来处理此问题相对也清晰了:根据是否采用代理了WKWebView的网络请求 , 我们需要不同的处理策略 。场景1-未代理WKWebView网络请求:Cookie完全由Networking进程管理 , WKWebView内可自闭环 。大部分情况下App进程也无需感知 , 如果确实需要感知 , 可以根据业务场景选择JS桥接、强制持久化等方案 。场景2-已代理WKWebView网络请求:Cookie大部分是由App进程来管理 , 此时应该采用何种同步策略 。
由于场景1中我们并未在生产环境中采用 , 故本文不打算做冒然分析 。下面主要聚焦于场景2来做进一部分分析 。在场景2下我们的核心目标:对于App进程中产生的Cookie , 能够及时同步到Networking进程:主要解决Reponse中存在"Set-Cookie"情况下 , JS端如何及时读取相关Cookie的问题 。对于WebContent中由JS产生的Cookie , 能及时同步到App进程:主要解决在JS端产生Cookie之后 , 我们如何保证在后续代理的网络请求中可被正常携带的问题 。
同步手段
在确认方案之前 , 我们首先要搞清楚一个问题:客户端侧Cookie来源有哪些?
对于App进程 , Cookie来源有两个:通过NSHTTPCookieStorage写入的 。在网络请求ResponseHeader中通过"Set-Cookie"写入的 。
对于WebContent进程 , 主要是JS通过document.cookie写入的(网络代理之后Set-Cookie不会在WKWebView进程中生效) 。
其次 , 我们要确认可用做同步的手段有哪些:
对于iOS11之后的系统 , 苹果已经为我们提供了WKHTTPCookieStore对象用来读写、监听WKWebView对应的Cookie , 可以直接使用 。
对于iOS11之前的系统 , 需要区分处理一下 。
从App进程同步到Networking进程 , 简单流程如下:第1步 , 需要把SessionCookie持久化 , 临时保存(注意需要标识 , 以供恢复) 。第2步 , 调用NSHTTPCookieStorage内部接口_saveCookies触发强制同步 。第3步 , 恢复临时保存的SessionCookie , 避免污染 。
由于Networking进程不会产生Cookie , 所以我们下面要做的是从WebContent进程同步Cookie:处理策略即在JS侧重写document.cookie方法 , 在JS修改cookies时 , 通过bridge将cookie传递到App进程 。
处理方案
在理清楚问题、目标和可用手段之后 , 我们即可总结出WKWebViewCookie相关问题的处理方案:对于iOS11及之后的系统 , 我们可以通过HOOKNSHTTPCookieStorage中读写Cookie的接口 , 并且监听网络请求中"Set-Cookie"关键字 , 在App进程Cookie发生变化时同步到WKWebView;同时通过WKHTTPCookieStore提供cookiesDidChangeInCookieStore能力来监听WKWebView中Cookie的变化 。对于iOS11之前的系统 , 处理策略类似 。但是我们需要过NSHTTPCookieStorage接口来做强制同步 , 并且需要注意恢复Cookie的SessionOnly属性;同时需要通过在JS侧重写document.cookie的方式 , 来感知WKWebView中Cookie的变化 。
特别注意:
采用iOS11之后方案处理时一定要注意 , 对WKHTTPCookieStore的操作会涉及到IPC通信 , 如果通信过于频繁、通信数据量过大 , 会产生明显的性能问题 。极端情况可能造成IPC模块异常 , 出现所有WKWebView都无法加载的情况 。比如典型的场景 , 如果一个页面请求较多、每个请求都带"Set-Cookie"、且业务上为了简单 , 每次把App进程的Cookie全量同步到WKWebView , 则Cookie过多时 , 有一定概率(暴力测试可复现)触发IPC异常 , 导致后续所有WKWebView实例都无法正常加载 , 只有App杀进程才可恢复 。建议在同步Cookie时 , 尽量按需同步变化的部分 。
3全面屏适配问题
全面屏适配问题相对不复杂 , 但因为WKWebView如UIWebView在表现上的不同 , 导致容易造成一些困扰 。