From 640a2c28b32ada68bb28432dc77b301779f338db Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 26 Jun 2023 14:58:16 -0700 Subject: [PATCH 1/2] Fixes for userAgent delay. Retrieved async now. --- Sources/Segment/Plugins/Context.swift | 10 ++++-- .../Platforms/Vendors/AppleUtils.swift | 33 +++++++++---------- Tests/Segment-Tests/Analytics_Tests.swift | 6 ++++ 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/Sources/Segment/Plugins/Context.swift b/Sources/Segment/Plugins/Context.swift index cb5346b4..0698ef0c 100644 --- a/Sources/Segment/Plugins/Context.swift +++ b/Sources/Segment/Plugins/Context.swift @@ -108,9 +108,6 @@ public class Context: PlatformPlugin { "width": screen.width, "height": screen.height ] - // user-agent - let userAgent = device.userAgent - context["userAgent"] = userAgent // locale if Locale.preferredLanguages.count > 0 { context["locale"] = Locale.preferredLanguages[0] @@ -147,6 +144,13 @@ public class Context: PlatformPlugin { "wifi": wifi ] + // user-agent + // BKS: This use to be in the static section, however it was discovered that on some platforms + // there can be a delay in retrieval. It has to be fetched on the main thread, so we've spun it off + // async and cache it when it comes back. + let userAgent = device.userAgent + context["userAgent"] = userAgent + // other stuff?? ... } diff --git a/Sources/Segment/Plugins/Platforms/Vendors/AppleUtils.swift b/Sources/Segment/Plugins/Platforms/Vendors/AppleUtils.swift index 8736addd..edf7162b 100644 --- a/Sources/Segment/Plugins/Platforms/Vendors/AppleUtils.swift +++ b/Sources/Segment/Plugins/Platforms/Vendors/AppleUtils.swift @@ -19,6 +19,7 @@ import WebKit internal class iOSVendorSystem: VendorSystem { private let device = UIDevice.current + @Atomic private static var asyncUserAgent: String? = nil override var manufacturer: String { return "Apple" @@ -65,17 +66,15 @@ 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 + // BKS: It was discovered that on some platforms there can be a delay in retrieval. + // It has to be fetched on the main thread, so we've spun it off + // async and cache it when it comes back. + if Self.asyncUserAgent == nil { + DispatchQueue.main.async { + Self.asyncUserAgent = WKWebView().value(forKey: "userAgent") as? String } } - - return userAgent + return Self.asyncUserAgent #else // webkit isn't on tvos return "unknown" @@ -198,6 +197,7 @@ import WebKit internal class MacOSVendorSystem: VendorSystem { private let device = ProcessInfo.processInfo + @Atomic private static var asyncUserAgent: String? = nil override var manufacturer: String { return "Apple" @@ -238,16 +238,15 @@ 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 + // BKS: It was discovered that on some platforms there can be a delay in retrieval. + // It has to be fetched on the main thread, so we've spun it off + // async and cache it when it comes back. + if Self.asyncUserAgent == nil { + DispatchQueue.main.async { + Self.asyncUserAgent = WKWebView().value(forKey: "userAgent") as? String } } - - return userAgent + return Self.asyncUserAgent } override var connection: ConnectionStatus { diff --git a/Tests/Segment-Tests/Analytics_Tests.swift b/Tests/Segment-Tests/Analytics_Tests.swift index e053bb8b..67d6ee49 100644 --- a/Tests/Segment-Tests/Analytics_Tests.swift +++ b/Tests/Segment-Tests/Analytics_Tests.swift @@ -123,6 +123,12 @@ final class Analytics_Tests: XCTestCase { let outputReader = OutputReaderPlugin() analytics.add(plugin: outputReader) + // prime the pump for userAgent, since it's retrieved async. + let vendorSystem = VendorSystem.current + while vendorSystem.userAgent == nil { + RunLoop.main.run(until: Date.distantPast) + } + waitUntilStarted(analytics: analytics) // add a referrer From baeb54055d55e73984ab851875709cb84329736b Mon Sep 17 00:00:00 2001 From: Brandon Sneed Date: Mon, 26 Jun 2023 15:32:35 -0700 Subject: [PATCH 2/2] Fix test for watchOS/Linux --- Tests/Segment-Tests/Analytics_Tests.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/Segment-Tests/Analytics_Tests.swift b/Tests/Segment-Tests/Analytics_Tests.swift index 67d6ee49..81d3d473 100644 --- a/Tests/Segment-Tests/Analytics_Tests.swift +++ b/Tests/Segment-Tests/Analytics_Tests.swift @@ -123,11 +123,13 @@ final class Analytics_Tests: XCTestCase { let outputReader = OutputReaderPlugin() analytics.add(plugin: outputReader) +#if !os(watchOS) && !os(Linux) // prime the pump for userAgent, since it's retrieved async. let vendorSystem = VendorSystem.current while vendorSystem.userAgent == nil { RunLoop.main.run(until: Date.distantPast) } +#endif waitUntilStarted(analytics: analytics)