Skip to content

Instantly share code, notes, and snippets.

@jscalo
Last active November 2, 2024 16:29
Show Gist options
  • Save jscalo/f08977fb1d685f6ec75b10e93bb408f7 to your computer and use it in GitHub Desktop.
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.
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
}
}
}
@jscalo
Copy link
Author

jscalo commented Nov 2, 2024

Usage:

let userAgent = try await GetUserAgent().get()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment