当前位置: 首页 > news >正文

【WKWebview】WKWebView Cookie 同步

个人实测:js注入的方式更靠谱一点

⌈iOS⌋WKWebView Cookie 同步的一种方式

屈服于 Apple 的“淫威”,开发者不得不将 App 的网页容器从 UIWebView 迁移到 WKWebView。我们在享受后者带来的性能和功能提升的同时,也被诸如 Cookie 同步、截图、白屏等问题弄得抓耳挠腮、狼狈不堪。无疑,上述问题会随着系统更新被逐渐修复,而开发者在产品系统适配的硬性要求下只得各凭本身缝缝补补,以期望减少在用户侧出现的问题。如题,下文我们对 Cookie 同步的情况进行一些说明,并总结出一种可行的方案。

问题回顾

简言之,WKWebView 的网络模块进程独立于 App 进程,App 进程通过 HTTPCookieStorage 管理的 Cookie 系统会自动使用 IPC 通信同步到 WKWebView。同 App 侧的 HTTPCookieStorage,WKWebView 的存储结构在代码层面表现为 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 算是一种老生常谈的同步手段了,它分为以下两个个步骤:

  1. 所有的 WKWebView 公用一个 WKProcessPool(不透明类型)和 WKWebsiteDataStore,后者使用 WKWebsiteDataStore.default() 返回的实例。
  2. 使用 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))
}
  1. 在用户退出登录时,清除 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 中是一种更为直接简单的方式。

相关文章:

【WKWebview】WKWebView Cookie 同步

个人实测:js注入的方式更靠谱一点 ⌈iOS⌋WKWebView Cookie 同步的一种方式 屈服于 Apple 的“淫威”,开发者不得不将 App 的网页容器从 UIWebView 迁移到 WKWebView。我们在享受后者带来的性能和功能提升的同时,也被诸如 Cookie 同步、截图…...

vue-router拦截器

在 Vue 项目中,vue-router 的路由拦截器和组件内部的路由拦截器(如 beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave)虽然都能拦截路由,但它们的作用范围和使用场景有所不同。下面是二者的区别总结: 1. 全局路…...

SpringBoot驱动的人事管理系统:高效办公新选择

1系统概述 1.1 研究背景 如今互联网高速发展,网络遍布全球,通过互联网发布的消息能快而方便的传播到世界每个角落,并且互联网上能传播的信息也很广,比如文字、图片、声音、视频等。从而,这种种好处使得互联网成了信息传…...

大数据干了什么?

1.大数据技术主要解决的问题是海量数据的 存储 和 查询...

android studio可用下载地址

AndroidDevTools - Android开发工具 Android SDK下载 Android Studio下载 Gradle下载 SDK Tools下载 在此记录一下...

HTTP 协议详解

HTTP 协议是 Web 的基石,它定义了客户端和服务器之间的通信规则。本文将深入地探讨 HTTP 的核心概念,包括工作原理、请求方法、状态码以及不同 HTTP 版本的演进。 一、HTTP 的工作原理 HTTP 协议基于客户端-服务器模型,遵循请求-响应的循环&…...

【力扣 | SQL题 | 每日四题】力扣534, 574, 2314, 2298

今天的每日四题比较简单,主要其中两题可以用窗口函数轻松解决。 1. 力扣534:游戏玩法分析3 1.1 题目: 表:Activity ----------------------- | Column Name | Type | ----------------------- | player_id | int | …...

Gitxray:一款基于GitHub REST API的网络安全工具

关于Gitxray Gitxray是一款基于GitHub REST API的网络安全工具,支持利用公共 GitHub REST API 进行OSINT、信息安全取证和安全检测等任务。 Gitxray(Git X-Ray 的缩写)是一款多功能安全工具,专为 GitHub 存储库而设计。它可以用于…...

Chrome(谷歌)浏览器 数据JSON格式美化 2024显示插件安装和使用

文章目录 目录 文章目录 安装流程 小结 概要安装流程技术细节小结 概要 没有美化的格式浏览器展示 美化之后效果图 安装流程 下载地址 https://github.com/gildas-lormeau/JSONVue 点击下载 下载成功,如图所示 解压文件 添加成功,如图所示 通过浏览器…...

关于相机的一些零碎知识点

热成像,英文为Thermal Imaging,例如型号500T,其实指的就是热成像500分辨率。 相机的CMOS,英文为Complementary Metal Oxide Semiconductor,是数码相机的核心成像部件,是一种互补金属氧化物导体器件。 DPI…...

看不懂来打我!让性能提升56%的Vue3.5响应式重构

前言 在Vue3.5版本中最大的改动就是响应式重构,重构后性能竟然炸裂的提升了56%。之所以重构后的响应式性能提升幅度有这么大,主要还是归功于:双向链表和版本计数。这篇文章我们来讲讲使用双向链表后,Vue内部是如何实现依赖收集和…...

Halcon 极坐标变换

(1)极坐标的展开:polar_trans_image_ext(Image : PolarTransImage : Row, Column, AngleStart, AngleEnd, RadiusStart, RadiusEnd, Width, Height, Interpolation : ) (2)极坐标的逆变换:polar_trans_ima…...

JavaScript进阶--深入面向对象

深入面向对象 编程思想 面向过程:多个步骤> 解决问题 性能较高,适合跟硬件联系很紧密的东西,如单片机 但代码维护成本高,扩展性差 面向对象:问题所需功能分解为一个一个的对象(分工合作)>…...

Python列表专题:list与in

Python是一种强大的编程语言,其中列表(list)是最常用的数据结构之一。列表允许我们存储多个元素,并且可以方便地进行各种操作。在Python中,in运算符被广泛用于检测元素是否存在于列表中。本文将深入探讨Python列表及其与in运算符的结合使用。 1. Python列表的基础 1.1 什…...

利用Microsoft Entra Application Proxy在无公网IP条件下安全访问内网计算机

在现代混合办公环境中,如何让员工能够从任何地方安全访问公司内部资源成为了企业的重要挑战。传统的VPN解决方案虽然可以满足需求,但有时配置复杂,并可能涉及公网IP的问题。为了解决这个问题,Microsoft Entra(原Azure …...

【IEEE独立出版 | 厦门大学主办】第四届人工智能、机器人和通信国际会议(ICAIRC 2024)

【IEEE独立出版 | 厦门大学主办】 第四届人工智能、机器人和通信国际会议(ICAIRC 2024) 2024 4th International Conference on Artificial Intelligence, Robotics, and Communication 2024年12月27-29日 | 中国厦门 >>往届均已成功见刊检索…...

C++ 内存布局 - Part5: 继承关系中 构造析构与vptr的调整

这里以单继承为例&#xff0c;汇编采用AT&T格式&#xff0c;先看示例代码&#xff1a; #include <iostream>class Base { public:Base() {std::cout << "Base Constructor, this ptr: " << this << std::endl;printVptr();}virtual ~Ba…...

BUG-AttributeError: ‘EnforcedForest‘ object has no attribute ‘node‘

File “/home/adt/miniconda3/envs/bevdet/lib/python3.7/site-packages/trimesh/scene/transforms.py”, line 224, in nodes_geometry ‘geometry’ in self.transforms.node[n]): AttributeError: ‘EnforcedForest’ object has no attribute ‘node’ networkx 2.6.3 pyp…...

Spring Boot 3 配置 Redis 兼容单例和集群

配置项 Spring Boot 3.x 的 redis 配置和 Spring Boot 2.x 是不一样的, 路径多了一个data spring:...data:redis:host: redis.hostport: redis.portpassword: redis.passworddatabase: redis.database兼容单例和集群的配置 开发时一般用一个Redis单例就足够, 测试和生产环境…...

unsat钱包签名算法解析

unsat钱包签名算法解析 在数字货币领域&#xff0c;安全性是至关重要的&#xff0c;而签名算法则是确保交易和信息不可伪造的基础。本文将深入解析 unsat 钱包中使用的签名算法&#xff0c;重点关注如何生成和验证消息签名。 1. 签名算法概述 unsat 钱包使用 ECDSA&#xff…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...

Java数组Arrays操作全攻略

Arrays类的概述 Java中的Arrays类位于java.util包中&#xff0c;提供了一系列静态方法用于操作数组&#xff08;如排序、搜索、填充、比较等&#xff09;。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序&#xff08;sort&#xff09; 对数组进行升序…...