Last active
November 2, 2024 16:29
-
-
Save jscalo/f08977fb1d685f6ec75b10e93bb408f7 to your computer and use it in GitHub Desktop.
Setting the user agent correctly on an iOS app's HTTP requests can be important, but it's a pain to get right. This lightweight solution creates an "offscreen" webView, loads a page, and grabs the user agent string. The result is cached so subsequent calls are instantaneous.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import WebKit | |
class GetUserAgent: NSObject, WKNavigationDelegate { | |
private static var cachedUserAgent: String? | |
private var continuation: CheckedContinuation<String, Error>? | |
private var webView: WKWebView? | |
func get() async throws -> String { | |
if let cached = Self.cachedUserAgent { | |
return cached | |
} | |
return try await withCheckedThrowingContinuation { continuation in | |
self.continuation = continuation | |
let configuration = WKWebViewConfiguration() | |
let webView = WKWebView(frame: .zero, configuration: configuration) | |
self.webView = webView | |
webView.navigationDelegate = self | |
// Load a lightweight URL to fetch the user agent | |
if let url = URL(string: "https://www.example.com") { | |
let request = URLRequest(url: url) | |
webView.load(request) | |
} else { | |
continuation.resume(throwing: NSError(domain: "GetUserAgent", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])) | |
self.continuation = nil | |
} | |
} | |
} | |
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { | |
// Execute JavaScript to get the navigator.userAgent string | |
webView.evaluateJavaScript("navigator.userAgent") { [weak self] result, error in | |
guard let self = self else { return } | |
if let error = error { | |
// Resume with error if JavaScript evaluation fails | |
self.continuation?.resume(throwing: error) | |
} else if let userAgent = result as? String { | |
// Resume with the retrieved user agent string | |
Self.cachedUserAgent = userAgent | |
self.continuation?.resume(returning: userAgent) | |
} else { | |
let unexpectedError = NSError( | |
domain: "GetUserAgent", | |
code: -2, | |
userInfo: [NSLocalizedDescriptionKey: "Unexpected result while fetching user agent"] | |
) | |
self.continuation?.resume(throwing: unexpectedError) | |
} | |
// Clean up | |
self.continuation = nil | |
self.webView = nil | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage: