From 4f21a78e4fff837d482b4b044b7e952cb9db6d02 Mon Sep 17 00:00:00 2001 From: Zach Dean Date: Mon, 12 Oct 2026 16:52:53 -0500 Subject: [PATCH] fix(ios): align user agent with analytics-swift getContext read the user agent by creating a WKWebView. The first web view in a process has to start WebKit, which blocks the main thread at launch (~290ms on an iPhone 12). Since Flutter 3.29 runs Dart on the platform thread, that also stalls Flutter frames. Build the string from the device model and OS version instead, as analytics-swift does since segmentio/analytics-swift#341, compute it once, and drop the WebKit import on iOS and macOS. --- .../segment_analytics/AppleUtils.swift | 43 ++++++------------- .../segment_analytics/AppleUtils.swift | 43 ++++++------------- 2 files changed, 28 insertions(+), 58 deletions(-) diff --git a/packages/core/ios/segment_analytics/Sources/segment_analytics/AppleUtils.swift b/packages/core/ios/segment_analytics/Sources/segment_analytics/AppleUtils.swift index bf2defa..af327d3 100644 --- a/packages/core/ios/segment_analytics/Sources/segment_analytics/AppleUtils.swift +++ b/packages/core/ios/segment_analytics/Sources/segment_analytics/AppleUtils.swift @@ -13,9 +13,6 @@ import Foundation import SystemConfiguration import UIKit -#if !os(tvOS) -import WebKit -#endif internal class iOSVendorSystem: VendorSystem { private let device = UIDevice.current @@ -64,23 +61,21 @@ internal class iOSVendorSystem: VendorSystem { } override var userAgent: String? { - #if !os(tvOS) - var userAgent: String? - - if Thread.isMainThread { - userAgent = WKWebView().value(forKey: "userAgent") as? String - } else { - DispatchQueue.main.sync { - userAgent = WKWebView().value(forKey: "userAgent") as? String - } - } - - return userAgent - #else - // webkit isn't on tvos + return iOSVendorSystem.generatedUserAgent + } + + private static let generatedUserAgent: String = { + #if os(tvOS) return "unknown" + #else + let v = ProcessInfo.processInfo.operatingSystemVersion + let version = v.patchVersion > 0 + ? "\(v.majorVersion)_\(v.minorVersion)_\(v.patchVersion)" + : "\(v.majorVersion)_\(v.minorVersion)" + let model = UIDevice.current.model.contains("iPhone") ? "iPhone" : "iPad" + return "Mozilla/5.0 (\(model); CPU \(model) OS \(version) like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148" #endif - } + }() override var connection: ConnectionStatus { return connectionStatus() @@ -186,7 +181,6 @@ internal class watchOSVendorSystem: VendorSystem { #if os(macOS) import Cocoa -import WebKit internal class MacOSVendorSystem: VendorSystem { private let device = ProcessInfo.processInfo @@ -230,16 +224,7 @@ internal class MacOSVendorSystem: VendorSystem { } override var userAgent: String? { - var userAgent: String? - if Thread.isMainThread { - userAgent = WKWebView().value(forKey: "userAgent") as? String - } else { - DispatchQueue.main.sync { - userAgent = WKWebView().value(forKey: "userAgent") as? String - } - } - - return userAgent + return "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko)" } override var connection: ConnectionStatus { diff --git a/packages/core/macos/segment_analytics/Sources/segment_analytics/AppleUtils.swift b/packages/core/macos/segment_analytics/Sources/segment_analytics/AppleUtils.swift index bf2defa..af327d3 100644 --- a/packages/core/macos/segment_analytics/Sources/segment_analytics/AppleUtils.swift +++ b/packages/core/macos/segment_analytics/Sources/segment_analytics/AppleUtils.swift @@ -13,9 +13,6 @@ import Foundation import SystemConfiguration import UIKit -#if !os(tvOS) -import WebKit -#endif internal class iOSVendorSystem: VendorSystem { private let device = UIDevice.current @@ -64,23 +61,21 @@ internal class iOSVendorSystem: VendorSystem { } override var userAgent: String? { - #if !os(tvOS) - var userAgent: String? - - if Thread.isMainThread { - userAgent = WKWebView().value(forKey: "userAgent") as? String - } else { - DispatchQueue.main.sync { - userAgent = WKWebView().value(forKey: "userAgent") as? String - } - } - - return userAgent - #else - // webkit isn't on tvos + return iOSVendorSystem.generatedUserAgent + } + + private static let generatedUserAgent: String = { + #if os(tvOS) return "unknown" + #else + let v = ProcessInfo.processInfo.operatingSystemVersion + let version = v.patchVersion > 0 + ? "\(v.majorVersion)_\(v.minorVersion)_\(v.patchVersion)" + : "\(v.majorVersion)_\(v.minorVersion)" + let model = UIDevice.current.model.contains("iPhone") ? "iPhone" : "iPad" + return "Mozilla/5.0 (\(model); CPU \(model) OS \(version) like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148" #endif - } + }() override var connection: ConnectionStatus { return connectionStatus() @@ -186,7 +181,6 @@ internal class watchOSVendorSystem: VendorSystem { #if os(macOS) import Cocoa -import WebKit internal class MacOSVendorSystem: VendorSystem { private let device = ProcessInfo.processInfo @@ -230,16 +224,7 @@ internal class MacOSVendorSystem: VendorSystem { } override var userAgent: String? { - var userAgent: String? - if Thread.isMainThread { - userAgent = WKWebView().value(forKey: "userAgent") as? String - } else { - DispatchQueue.main.sync { - userAgent = WKWebView().value(forKey: "userAgent") as? String - } - } - - return userAgent + return "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko)" } override var connection: ConnectionStatus {