a站在线观看人数在哪,免费网络推广平台,莆田自助建站软件,宾利棋牌在哪个网站做的广告个人实测#xff1a;js注入的方式更靠谱一点
⌈iOS⌋WKWebView Cookie 同步的一种方式
屈服于 Apple 的“淫威”#xff0c;开发者不得不将 App 的网页容器从 UIWebView 迁移到 WKWebView。我们在享受后者带来的性能和功能提升的同时#xff0c;也被诸如 Cookie 同步、截图…个人实测js注入的方式更靠谱一点
⌈iOS⌋WKWebView Cookie 同步的一种方式
屈服于 Apple 的“淫威”开发者不得不将 App 的网页容器从 UIWebView 迁移到 WKWebView。我们在享受后者带来的性能和功能提升的同时也被诸如 Cookie 同步、截图、白屏等问题弄得抓耳挠腮、狼狈不堪。无疑上述问题会随着系统更新被逐渐修复而开发者在产品系统适配的硬性要求下只得各凭本身缝缝补补以期望减少在用户侧出现的问题。如题下文我们对 Cookie 同步的情况进行一些说明并总结出一种可行的方案。
问题回顾
简言之WKWebView 的网络模块进程独立于 App 进程App 进程通过 HTTPCookieStorage 管理的 Cookie 系统会自动使用 IPC 通信同步到 WKWebView。同 App 侧的 HTTPCookieStorageWKWebView 的存储结构在代码层面表现为 WKWebsiteDataStore(iOS 9) 和 WKHTTPCookieStore(iOS 11)前者拥有后者。上述过程咋一看并不会有什么问题但正因为是 IPC 来完成进程通信它必然是异步执行的即感官上的同步延迟。如果在这之前就进行需要验证 Cookie 的 WebView 请求就是发现因缺少 Cookie 导致的鉴权失败。
一个典型的 是用户通过通知等方式启动 App 打开一个和用户态关联的 Web URL在用户登录完成之后登录接口会进行 Set-Cookie 操作写入用户的 auth_token 等数据立即打开网页。此时会发现网页要求用户重新登录如果通过 Charles 抓包进行观察的话会发现此时 Cookies 中并没有上述 auth_token 等与用户态关联的鉴权信息。
换汤不换药的 WKHTTPCookieStore
从 iOS 11 开始我们可以开始用官方的补救措施WKHTTPCookieStore。它与 HTTPCookieStorage 接口很相似我们或许很自然地想到用下面这样一段代码来同步 Cookie
let group DispatchGroup()
HTTPCookieStorage.shared.cookies?.forEach {group.enter()webView.configuration.websiteDataStore.httpCookieStore.setCookie($0) {group.leave()}
}
group.notify(queue: .main) {webView.load(urlRequest)
}在实践过程的测试初期并没有发现什么异常。而在内测阶段**App 中存在很多的网页场景且每次加载之前都会进行上述的同步操作就会几率性出现 setCookie 的 completionHandler 不执行的情况从而导致当前网页且后续所有网页都无法正常加载**从 WKHTTPCookieStore 设置 Cookie 的接口不难看出它本质上还是通过 IPC 异步与 Web 进程通信。当同步的 Cookie 操作频繁执行时会导致 App 与 Web 进程间通信出现异常而这个度很难去把控所以放弃这种方式。
这里有提到监听 NSHTTPCookieManagerCookiesChangedNotification 来修改 WKHTTPCookieStore 的方式诸君可自行尝试。
从一而终JS 注入
通过 Javascript 注入 Cookie 算是一种老生常谈的同步手段了它分为以下两个个步骤
所有的 WKWebView 公用一个 WKProcessPool不透明类型和 WKWebsiteDataStore后者使用 WKWebsiteDataStore.default() 返回的实例。使用 WKUserScript 向 WKWebView 的 WKUserContentController 中注入 Javascript
private func _syncCookies() {// https://stackoverflow.com/a/32845148var scripts: [String] [var cookieNames document.cookie.split(; ).map(function(cookie) { return cookie.split()[0] } )]// Cookie 过期处理由系统进行管理不进行手动删除操作HTTPCookieStorage.shared.cookies?.forEach {// 假设系统的 Cookie 同步行为没有完成如果过滤具有 httpOnly 标示的 cookie就会在后续网络请求中 cookie 丢失的问题。// 即使在首次 loadRequest 中直接设置请求头的 cookie 字段注入该 cookie。// guard $0.isHTTPOnly false else { return }// 当不存在此 cookie 时才进行设置避免注入同名 cookiescripts.append(if (cookieNames.indexOf(\($0.name)) -1) { document.cookie\($0.javaScriptString); })}let source scripts.joined(separator: ;\n)userContentController.addUserScript(WKUserScript(source: source,injectionTime: .atDocumentStart,forMainFrameOnly: false))
}在用户退出登录时清除 WKWebView 数据
WKWebsiteDataStore.default().removeData(ofTypes: WKWebsiteDataStore.allWebsiteDataTypes(),modifiedSince: Date(timeIntervalSince1970: 0.0),completionHandler: completion
)pool nil// Important: 销毁所有的 WKWebView如果有常驻 WKWebView 则重建。在实践工程中发现几率性出现 Cookie 残留即使已经执行了清除所有数据的操作。按部就班之后你会发现这个方式和完全靠系统来处理存在同样的问题存在延迟具体表现为第一次打开网页 Cookie 没有第二次打开又有了。WTF事实上这算是 WKUserScript 注入的一个坑了。注意看我们注入 Javascript 的时机是 atDocumentStart文档对它的解释是这样的A constant to inject the script after the creation of the webpage’s document element, but before loading any other content.从字面理解来看在 HTML DOM 加载过程中WKWebView 的网络请求就会带上这些 Cookie但实际上并没有。
从本质上来看App 侧注入的 document.cookie 是给 Web 侧增加 Cookie 环境。而从上面的操作结果来看并不代表它在注入完成之后就会立刻生效。在此我们可以在后台预先加载一个 URL指向一个空白的能正常加载成功的页面即可如 xxxx://xxxx/ios/cookie/sync来完成 Cookie 环境的同步然后再请求实际的 Web URL 来解决这个问题。
总结
从 UIWebView 时期与 App 公用 HTTPCookieStorage 到现在 WKWebView 的泾渭分明最可靠的 Cookie 同步方式始终都是系统默认方案。无奈后者的技术架构迫使我们做一些“骚操作”去促使系统自动完成全文单从 App 侧同步到 Web 侧的一些实践过程进行了阐述最终总结出 Preload Javascript Clean 的一种基本可行的方式。而从 Web 侧到 App 侧没有做任何额外的操作而是完全依赖于系统行为这或许埋下了一些隐患但到目前来说我们没有遇到相关问题。其实针对于服务器渲染的前端页面在充分考虑安全性的前提下将 Cookie 直接塞到 URL 的 query 中是一种更为直接简单的方式。