Reputation: 14404
Is there a way on iOS to get the user agent of the device? I don't want to hard code it since I need the user agent for all devices and I need to append the user agent to a URL.
Thanks.
Upvotes: 19
Views: 36647
Reputation: 2181
Objective-C
WKWebView *webView = [WKWebView new];
res = [webView valueForKey:@"userAgent"];
Swift
let ua = WKWebView().value(forKey: "userAgent")
Dont forget to import WebKit đ
Upvotes: 1
Reputation: 11184
Mobile application in every request must send his User-Agent
header with build version and device information
So, user agent should be like:
User-Agent: <AppName>/version (<system-information>) <platform> (<platform-details>) <extensions>
For iOS:
User-Agent: <AppName/<version> (<iDevice platform>; <Apple model identifier>; iOS/<OS version>) CFNetwork/<version> Darwin/<version>
How to get each of the components?
Headers Key - u can hardcode or use some constant values
AppName and version - grab from Info.plist
let infoPlist = try? PListFile<InfoPlist>()
let appName = infoPlist.data.bundleName
let version = infoPlist.data.versionNumber
let build = infoPlist.data.buildNumber
Info about Device
modelName
- you can obtain like described here
let modelName = UIDevice.current.modelName
other components:
let platform = UIDevice.current.systemName
let operationSystemVersion = ProcessInfo.processInfo.operatingSystemVersionString
CFNetwork version
static var cfNetworkVersion: String? {
guard
let bundle = Bundle(identifier: "com.apple.CFNetwork"),
let versionAny = bundle.infoDictionary?[kCFBundleVersionKey as String],
let version = versionAny as? String
else { return nil }
return version
}
Darwin Version
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.release)
let darvinVersionString = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8,
value != 0 else {
return identifier
}
return identifier + String(UnicodeScalar(UInt8(value)))
}
Result:
MyApp/1.8.199 (iOS; iPhone XS; Version 13.3 (Build 17C45)) CFNetwork/1121.2.1 Darvin/19.3.0
Upvotes: 14
Reputation: 490
(iOS 8.0, *)
Since UIWebView is deprecated in iOS 12, you should use WKWebView instead.
Since WKWebView.evaluateJavaScript(_:) result is now async, this implementation solve a common requirement to have userAgent available in your own REST api call.
import WebKit
class UAString {
static var userAgent : String = ""
@discardableResult init(view parent: UIView) {
if UAString.userAgent.isEmpty {
let webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
webView.translatesAutoresizingMaskIntoConstraints = false
parent.addSubview(webView)
webView.evaluateJavaScript("navigator.userAgent") { result, _ in
UAString.userAgent = result as? String ?? ""
}
}
}
}
Now last part you can implement this class in your initial view controller as follow:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UAString(view: self.view)
}
then you can access the attribute as UAString.userAgent
Upvotes: 3
Reputation: 3817
Swift 3.x, 4.x, 5.x, & above
As sometime traditional UIWebView get's memory leaked so instead use always WKWebView (far better from UIWebView)
import WebKit
var webViewForUserAgent: WKWebView?
and get userAgent by calling below function & you can also set it to your other variable
func getUserAgent() {
webViewForUserAgent = WKWebView() // must initialize
webViewForUserAgent?.evaluateJavaScript("navigator.userAgent") { (result, error) in
//
if error != nil {
print("Error occured to get userAgent")
return
}
//
if let unwrappedUserAgent = result as? String {
print("userAgent: \(unwrappedUserAgent)")
} else {
print("Failed to get userAgent")
}
}
}
Upvotes: 0
Reputation: 16
A simpler way to ascertain the user agent in iOS is to get it directly from a UIWebView using the accepted answer to this SO post.But this way has two disadvantages:
1ăUIWebView's first allocation may take too much time in initializing webview context.
2ăthe code must be executed in main thread. This may stuck main thread.
If you know the tricks of how to use private methods while avoiding the refusal of App Store Review.
You can try the following code:
#define CALL_PRIVATE_INSTANCEMETHOD(x,sel,q)\ {\ SEL selector = NSSelectorFromString([NSString stringWithFormat:@"%@",@#sel]);\ if ([x respondsToSelector:selector]) {\ _Pragma("clang diagnostic push")\ _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")\ q=[x performSelector:selector];\ _Pragma("clang diagnostic pop")\ }\ }\ #define CALL_PRIVATE_CLASSMETHOD_ONEPARAM(x,sel,p,q)\ {\ SEL selector = NSSelectorFromString([NSString stringWithFormat:@"_%@:",@#sel]);\ if ([x respondsToSelector:selector]) {\ _Pragma("clang diagnostic push")\ _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"")\ q=[x performSelector:selector withObject:p];\ _Pragma("clang diagnostic pop")\ }\ }\ + (NSString *)standardUserAgent{ NSString *buildVersion = nil; CALL_PRIVATE_INSTANCEMETHOD([UIDevice currentDevice], buildVersion,buildVersion); Class webViewCls = NSClassFromString([NSString stringWithFormat:@"%@%@",@"Web",@"View"]); NSString *standardUA = nil; NSString *versions = [NSString stringWithFormat:@"Mobile/%@",buildVersion]; CALL_PRIVATE_CLASSMETHOD_ONEPARAM(webViewCls, standardUserAgentWithApplicationName,versions,standardUA); return standardUA; }
Upvotes: -1
Reputation: 635
You donât actually need to make the request in order to get the user-agent. Just return NO from the following delegate method and retain the user-Agent header:
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
It might look something like this:
-(BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
userAgent = [[request valueForHTTPHeaderField:@"User-Agent"] copy];
NSLog(@"user-agent: %@", userAgent);
_webView.delegate = nil;
[_webView release];
return NO;
}
Upvotes: 6
Reputation:
A simpler way to ascertain the user agent in iOS is to get it directly from a UIWebView
using the accepted answer to this SO post. To quote that answer:
The solution was to create a UIWebView and then just use javascript to pull out the user agent.
UIWebView* webView = [[UIWebView alloc] initWithFrame:CGRectZero]; NSString* secretAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
Upvotes: 44