乐于分享
好东西不私藏

iOS 26 之后,你的 iOS 版本检测代码可能已经不准了

iOS 26 之后,你的 iOS 版本检测代码可能已经不准了

iOS 26发布后,Safari的UA字符串不再更新系统版本,这一旨在保护用户隐私的改变,却让开发者依赖了近二十年的版本判断逻辑彻底失效。

今年初,有人发现 StatCounter 的数据显示 iOS 26 的升级率只有 16%。

这个数字让人困惑。苹果用户向来升级积极,怎么会这么低?

去查了才发现——数据本身就是错的。


问题出在一件很多开发者还不知道的事上。

iOS 26 发布之后,Safari 的 UA 字符串里,系统版本号不再更新了。

你问它”你在什么系统上跑”,它告诉你 18.7。

但实际上它跑在 iOS 26 上。

StatCounter 读取 UA 里的版本号来统计用户系统分布,于是大量 iOS 26 用户被归进了”iOS 18″的桶里。

iOS 上 Safari 流量占比超过 70%大多数 iOS 26 用户被错误归类,导致升级率数据严重失真

但事情比这还复杂。

同一台 iPhone,不同浏览器给你的答案完全不一样。

以下是同一台 iPhone 上实测的两条 UA,同样是 iOS 26.5:

// SafariMozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) ... Version/26.5 Mobile/15E148 Safari/604.1// ChromeMozilla/5.0 (iPhone; CPU iPhone OS 26_5_0 like Mac OS X) ... CriOS/149.0.7827.137 Mobile/15E148 Safari/604.1

Safari 告诉你系统是 18.7。

Chrome 告诉你系统是 26.5.0。

同一台手机,差了八个大版本。

UA 冻结前后对比

为什么会这样?

Safari 是苹果自己的浏览器,它主动选择了冻结版本号——出于隐私保护的考量,不想让网站通过 UA 追踪用户的具体系统版本。

Chrome 是第三方浏览器,没有跟进这个策略,还是老老实实上报真实版本。

大致分两类:

跟 Safari 一样冻结 CPU 字段的——Opera、Edge iOS,以及部分国产浏览器。

直接写真实版本的——Chrome、UC 浏览器。

还有更特别的,百度 iOS 把真实版本藏在了自己的私有字段里,不按任何通用规则来。

所以现在的情况是:同一台 iPhone,不同浏览器,拿到的版本号可能完全不同,需要不同的解析策略。以前一个正则搞定所有情况的时代,过去了。


但 Safari 也没有完全不给你信息。

注意看这行:

Version/26.5

CPU 字段冻结了,但 Version/ 字段还是真实的 Safari 版本号。

而 iOS 26 之后,苹果统一了版本号——Safari 26 对应 iOS 26,Safari 的大版本号就等于 iOS 的大版本号。

所以如果你需要判断用户是不是在 iOS 26 及以上,读 Version/ 字段,比读 CPU iPhone OS 可靠得多。


哪些代码正在悄悄出错?

// ❌ 这个判断在 Safari 上永远拿到 18,不是真实版本const match = ua.match(/OS ([\d_]+) like Mac OS X/)const iosVersion = match?.[1].replace(/_/g, '.')// ❌ 这个判断永远不会执行,因为 Safari 从 18 直接跳到了 26if (iosVersion >= 19) {  enableFeature()}

如果你的代码里有类似的版本号判断,在 Safari 用户身上,它已经在返回错误结果了。

用 Chrome 访问的用户不受影响,但 iOS 上 Safari 的流量占比超过 70%,这意味着大多数 iOS 用户都在走这条路径。


还有一件事值得一提。

iOS 上没有 Client Hints

Android 和 Windows 上,当 UA 不可靠的时候,还可以用 Client Hints API 拿到真实的系统版本。

但 iOS 上的所有浏览器都必须使用苹果的 WebKit 引擎,而 WebKit 不支持 Client Hints。

所以在 iOS 上,你只能靠 UA 字符串本身解决这个问题,没有其他退路。


正确的思路是什么?

判断功能支不支持,用特性检测,不要用版本号。

错误做法 vs 正确做法的代码对比图

如果你真的需要知道 iOS 大版本,读 Version/ 字段,不要读 CPU iPhone OS

但要注意,Version/ 只在 Safari 上等于 iOS 版本,Chrome 和其他浏览器不适用这个规则。

这就是为什么现在的 UA 解析比以前复杂——不同浏览器需要不同的解析策略,没有一个万能的正则能处理所有情况。


把 iOS 26 的 Safari UA 丢进解析工具,结果会告诉你版本是 18.7。

感兴趣可以用自己的浏览器试一下:https://yangtianxia.github.io/ua-browser/playground

这不是工具的问题,它如实读出了 UA 里的内容。

真正的变化是:以前 UA 里的版本号是事实,现在它只是一个参考——而且不同浏览器的参考价值还不一样。

这不是一个能等着别人帮你解决的问题。如果你的代码依赖 iOS 版本号做判断,现在就是检查它的时候了。