iOS问题记录 - iOS 17通过NSUserDefaults设置UserAgent无效
文章目录
- 前言
- 开发环境
- 问题描述
- 问题分析
- 解决方案
- 最后
前言
最近维护一个老项目时遇到的问题。说起这老项目我就有点头疼,一个快十年前的项目,这么说你可能不觉得有什么,但是你想想Swift也才发布不到十年(2014年6月发布,现2023年12月)。
开发环境
- Xcode: 15.1
- iOS: 17.2
问题描述
项目运行在iOS 17.2设备时,应用内网页无法成功获取设置后的UserAgent
。
项目中设置UserAgent
的关键源码:
[self.webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) {NSString *userAgent = [NSString stringWithFormat:@"%@", result];NSString *newUserAgent = [userAgent stringByAppendingString:@" App/1.0.0"];[[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent": newUserAgent}];
}];
问题分析
从项目源码看,设置UserAgent
是通过NSUserDefaults
实现的。大致操作如下:
- 首先应用启动后创建一个
WKWebView
实例对象,无需加载任何网页 - 然后通过
navigator.userAgent
获取当前的UserAgent
并修改 - 接着调用
registerDefaults
方法将修改后的UserAgent
注册到NSUserDefaults
,成为应用的默认设置 - 最后销毁该
WKWebView
实例对象
经过以上操作,后续创建WKWebView
实例对象时都能从NSUserDefaults
中获取到修改后的UserAgent
用于初始化,从而实现全局设置。需要注意一点,registerDefaults
方法设置默认值的操作不会进行持久化存储,所以应用每次启动都需要设置一遍。
虽然理了一遍设置逻辑感觉没什么问题,但是这个方法有点老了,现在一般通过customUserAgent
属性设置,难道这个方法过时了?
为了排除其他可能存在的干扰,新建一个iOS项目用于测试,源码如下:
import UIKit
import WebKitclass ViewController: UIViewController, WKNavigationDelegate {private let htmlString = """<html><head><meta name="viewport" content="width=device-width"><style>button {font-size: 24px;}</style><script>function getUserAgent() {var userAgent = navigator.userAgent;var paragraph = document.createElement('p');paragraph.textContent = 'UserAgent: ' + userAgent;document.body.appendChild(paragraph);}</script></head><body style="text-align: center;"><button οnclick="getUserAgent()">获取 UserAgent</button></body></html>"""private var webView: WKWebView!override func viewDidLoad() {super.viewDidLoad()// 在WKWebView初始化前设置UserAgentUserDefaults.standard.register(defaults: ["UserAgent": "App/1.0.0"])// 创建WKWebViewlet webViewConfiguration = WKWebViewConfiguration()webView = WKWebView(frame: view.bounds, configuration: webViewConfiguration)webView.navigationDelegate = selfview.addSubview(webView)// 加载HTMLwebView.loadHTMLString(htmlString, baseURL: nil)}
}
iOS 17.2测试结果:
iOS 16.4测试结果:
实测iOS 17.0和iOS 17.2测试结果一样,现在可以确定从iOS 17开始,通过NSUserDefaults
设置UserAgent
都无法生效。初步判断,这个设置方法在iOS 17及以上过时了,个人猜测可能是WKWebView
初始化时不再从NSUserDefaults
获取默认值导致的(今天天太冷了,实在扛不住,后面有机会再翻翻相关源码尝试验证猜测)。
既然这个方法失效了,那在iOS 17上通过customUserAgent
属性设置能正常生效吗?
对前面的测试源码做简单修改,页面加载完成后自动获取一次未修改的UserAgent
,然后再修改UserAgent
并通过customUserAgent
属性设置,接着手动点击按钮获取一次UserAgent
,最后对比两次获取结果判断是否设置成功。
import UIKit
import WebKitclass ViewController: UIViewController, WKNavigationDelegate {private let htmlString = """<html><head><meta name="viewport" content="width=device-width"><style>button {font-size: 24px;}</style><script>function getUserAgent() {var userAgent = navigator.userAgent;var paragraph = document.createElement('p');paragraph.textContent = 'UserAgent: ' + userAgent;document.body.appendChild(paragraph);}/* 页面加载完成后获取一次UserAgent */window.onload = function() {getUserAgent();};</script></head><body style="text-align: center;"><button οnclick="getUserAgent()">获取 UserAgent</button></body></html>"""private var webView: WKWebView!override func viewDidLoad() {super.viewDidLoad()// 创建WKWebViewlet webViewConfiguration = WKWebViewConfiguration()webView = WKWebView(frame: view.bounds, configuration: webViewConfiguration)webView.navigationDelegate = selfview.addSubview(webView)// 加载HTMLwebView.loadHTMLString(htmlString, baseURL: nil)}func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {// 获取当前的UserAgentwebView.evaluateJavaScript("navigator.userAgent") { (result, error) inguard let userAgent = result as? String else {return}let newUserAgent = userAgent + " App/1.0.0"// 设置UserAgentwebView.customUserAgent = newUserAgent}}
}
测试结果:
从测试结果看,通过customUserAgent
属性设置UserAgent
一切正常。不过这种方法不好实现全局设置,每次创建新的WKWebView
实例对象都需要再设置一遍。
解决方案
通过NSUserDefaults
设置UserAgent
改为通过customUserAgent
属性设置UserAgent
,更多详情请参考前面的问题分析。
最后
如果这篇文章对你有所帮助,点赞👍收藏🌟支持一下吧,谢谢~
本篇文章由@crasowas发布于CSDN。
相关文章:

iOS问题记录 - iOS 17通过NSUserDefaults设置UserAgent无效
文章目录 前言开发环境问题描述问题分析解决方案最后 前言 最近维护一个老项目时遇到的问题。说起这老项目我就有点头疼,一个快十年前的项目,这么说你可能不觉得有什么,但是你想想Swift也才发布不到十年(2014年6月发布࿰…...

linux的一些典型面试题解读
目录 前言1 Linux 文件系统2 Shell 编程3 进程管理4 用户和权限管理5 软件包管理6 网络配置7 系统监控和日志8 存储管理9 安全性10 常见命令11 系统启动流程12 Linux 进程间通信方式13 Linux 中的 I/O 多路复用14 Shell 脚本优化与调试15 Linux 文件权限与 ACL16 Linux 中的环境…...

tortoisesvn各版本下载链接
https://tortoisesvn.net 无法访问最新版本下载 TortoiseSVN download | SourceForge.net 所有版本下载 TortoiseSVN - Browse Files at SourceForge.net...

[自动化运维工具]ansible简单介绍和常用模块
ansible 源操作主机功能 自动化运维(playbook剧本yaml) 是基于python开发的一个配置管理和应用部署工具,在自动化运维中,现在还是异军突起 ansible能批量配置,部署,管理上千台主机,类似于xshell…...

记一次渗透测试信息收集-越权
目录 一、信息收集 子域名收集 存活探测 二、越权 越权一 越权二 一、信息收集 子域名收集 使用subfinder进行子域名收集 语法:subfinder.exe -d xx.com -all -o qq1.txt -v //结合自己渗透经验,多渠道收集子域名,汇总去重。 …...

Flink系列之:Table API Connectors之JSON Format
Flink系列之:Table API Connectors之JSON Format 一、JSON Format二、依赖三、创建一张基于 JSON Format 的表四、Format 参数五、数据类型映射关系 一、JSON Format JSON Format 能读写 JSON 格式的数据。当前,JSON schema 是从 table schema 中自动推…...

2018年第七届数学建模国际赛小美赛B题世界杯足球赛的赛制安排解题全过程文档及程序
2018年第七届数学建模国际赛小美赛 B题 世界杯足球赛的赛制安排 原题再现: 有32支球队参加国际足联世界杯决赛阶段的比赛。但从2026年开始,球队的数量将增加到48支。由于时间有限,一支球队不能打太多比赛。因此,国际足联提议改变…...

【为数据之道学习笔记】5-7五类数据主题联接的应用场景
在数字化转型的背景下,华为的数据消费已经不再局限于传统的报表分析,还要支持用户的自助分析、实时分析,通过数据的关联,支持业务的关联影响分析以及对目标对象做特征识别,进行特定业务范围圈定、差异化管理与决策等。…...

得帆信息创始人-张桐,受邀出席 BV百度风投AIGC主题论坛
近日,得帆信息创始人兼CEO张桐,作为百度风投被投代表企业创始人受邀出席“向未来,共成长” BV百度风投AIGC主题论坛。 与包括上海市徐汇区相关部门领导、百度集团相关事业部负责人及代表,以及来自国寿资本、中网投、麦顿投资的投资…...

云原生之深入解析减少Docker镜像大小的优化技巧
一、什么是 Docker? Docker 是一种容器引擎,可以在容器内运行一段代码,Docker 镜像是在任何地方运行应用程序而无需担心应用程序依赖性的方式。要构建镜像,docker 使用一个名为 Dockerfile 的文件,Dockerfile 是一个包…...

记一次java for循环改造多线程的操作
背景 今天在开发质量平台时需要获取某些数据,要请求公司某个工程的OpenAPI接口A。此接口为返回通用数据的接口,且接口本身的RT都在2~3秒之间。使用该接口,需要进行两次循环获取,然后对返回数据进行处理组装࿰…...

Java面试整理-Java复制
Java复制 在Java中,复制对象或数据通常涉及不同的场景和方法。以下是几种常见的复制情况及其相关方法: 基本数据类型的复制:基本数据类型(如int, double, char等)在Java中是通过值传递的。当你将一个基本数据类型的值赋给另一个变量时,实际上是创建了一个新的值。 int a …...

wsl kafka的简单应用
安装并配置单机版kafka所需环境 wsl2 环境可用性较高,如下介绍在该环境中安装单机版本kafka的详细过程。 启动命令行工具启动wsl:wsl --user root --cd ~,(以root用户启动,进入wsl后当前路径为~“用户主目录”&#…...

2023年国赛高教杯数学建模D题圈养湖羊的空间利用率解题全过程文档及程序
2023年国赛高教杯数学建模 D题 圈养湖羊的空间利用率 原题再现 规模化的圈养养殖场通常根据牲畜的性别和生长阶段分群饲养,适应不同种类、不同阶段的牲畜对空间的不同要求,以保障牲畜安全和健康;与此同时,也要尽量减少空间闲置所…...

Flink系列之:Table API Connectors之Raw Format
Flink系列之:Table API Connectors之Raw Format 一、Raw Format二、示例三、Format 参数四、数据类型映射 一、Raw Format Raw format 允许读写原始(基于字节)值作为单个列。注意: 这种格式将 null 值编码成 byte[] 类型的 null。这样在 ups…...

社交网络分析3:社交网络隐私攻击、保护的基本概念和方法 + 去匿名化技术 + 推理攻击技术 + k-匿名 + 基于聚类的隐私保护算法
社交网络分析3:社交网络隐私攻击、保护的基本概念和方法 去匿名化技术 推理攻击技术 k-匿名 基于聚类的隐私保护算法 写在最前面社交网络隐私泄露用户数据暴露的途径复杂行为的隐私风险技术发展带来的隐私挑战经济利益与数据售卖防范措施 社交网络 用户数据隐私…...

2023大湾区汽车创新大会在深圳坪山开幕
12月15日,2023大湾区汽车创新大会在深圳坪山开幕。 本次大会是由广东省科学技术厅、深圳市发展和改革委员会、深圳市工业和信息化局、中共深圳市新能源和智能网联汽车产业链委员会、坪山区人民政府指导,北京理工大学深圳汽车研究院、广东省大湾区新能源汽…...

Graylog 中日志级别及其对应的数字
在 Graylog 中,日志级别 level 通常使用数字表示,数字越低表示日志级别越高。以下是常见的日志级别及其对应的数字表示: DEBUG(调试):对应数字 7。INFO(信息):对应数字 …...

智能手表上的音频(五):录音
上篇讲了语音通话,本篇讲录音。录音功能就是把录到的音频保存成文件。保存文件的格式支持两种:一是PCM(16K采样)的WAV格式,二是AMR-NB(8k采样)的AMR格式。WAV格式简单:44字节的文件头PCM 数据,示…...

2023.12.17 关于 Redis 的特性和应用场景
目录 引言 Redis 特性 内存中存储数据 可编程性 可扩展性 持久化 支持集群 高可用性 Redis 优势 Redis 用作数据库 Redis 相较于 MySQL 优势 Redis 相较于 MySQL 劣势 Redis 用作缓存 典型场景 Redis 存储 session 信息 Redis 用作消息队列 初心 消息队列的…...

智能优化算法应用:基于社会群体算法3D无线传感器网络(WSN)覆盖优化 - 附代码
智能优化算法应用:基于社会群体算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于社会群体算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.社会群体算法4.实验参数设定5.算法结果6.…...

Kotlin 笔记 -- Kotlin 语言特性的理解(二)
都是编译成字节码,为什么 Kotlin 能支持 Java 中没有的特性? kotlin 有哪些 Java 中没有的特性: 类型推断、可变性、可空性自动拆装箱、泛型数组高阶函数、DSL顶层函数、扩展函数、内联函数伴生对象、数据类、密封类、单例类接口代理、inter…...

数据结构【1】:数组专题
一、定义 数组是编程中一种强大的数据结构,它允许您存储和操作相同类型元素的集合。在 Python 中,数组是通过数组模块创建的,该模块提供了一个简单的接口来创建、操作和处理数组。 二、创建数组 在 Python 中,可以使用内置的 a…...

【Spring】Spring 事务
Spring 事务 文章目录 Spring 事务1. 简介2. Spring事务管理器3. 基本使用4. 属性剖析5. 声明式事务问题场景5.1 事务不生效5.2 事务不回滚5.3 大事务问题 6. 编程式事务 1. 简介 编程式事务:指手动编写程序来管理事务,即通过编写代码的方式直接控制事务…...

Ubuntu 虚拟机环境,编译AOSP源码
环境 : VMware虚拟机 Ubuntu 20.04.3 LTS 搭建配置开发环境 sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g-multilib libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl…...

2023.12.18杂记
今天特地搜了一下国内不错的博客网站,本来想在掘金上写的,但是怕被人喷(,所以还是决定在csdn上写了哈哈哈。 这篇文章主要整理一下我今天写代码时遇到的疑惑以及记录一下思考过程吧。 第一个注意的地方,我们的get查询…...

智能优化算法应用:基于阿基米德优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码
智能优化算法应用:基于阿基米德优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于阿基米德优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.阿基米德优化算法4.实验参数设定…...

K8s内容器拓扑图工具
1.背景:随着线上容器越来越多,需要一个可视化的方式展示各个容器之间的拓扑图。 2.需求:轻量级,部署方便。 3.部署 helm repo add groundcover https://helm.groundcover.com/ helm repo update helm install caretta --namespa…...

掌握 Babel:让你的 JavaScript 与时俱进(上)
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…...

Mysql进阶-InnoDB引擎事务原理及MVCC
事务原理 事务基础 事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系 统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。 事务的四大特性: 原子性(A…...