如何在 iOS 上获取用户代理?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8579019/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get the user agent on iOS?
提问by David
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.
iOS 上有没有办法获取设备的用户代理?我不想对其进行硬编码,因为我需要所有设备的用户代理,并且需要将用户代理附加到 URL。
Thanks.
谢谢。
回答by
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:
确定 iOS 中的用户代理的一种更简单的方法是UIWebView
使用此 SO post的已接受答案直接从 a 中获取它。引用那个答案:
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"];
解决方案是创建一个 UIWebView,然后只使用 javascript 来拉出用户代理。
UIWebView* webView = [[UIWebView alloc] initWithFrame:CGRectZero]; NSString* secretAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
回答by aimless
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:
您实际上不需要发出请求来获取用户代理。只需从以下委托方法返回 NO 并保留 user-Agent 标头:
-(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;
}
回答by Giuseppe Mazzilli
(iOS 8.0, *)
(iOS 8.0, *)
Since UIWebView is deprecated in iOS 12, you should use WKWebView instead.
由于 UIWebView 在 iOS 12 中已弃用,您应该改用 WKWebView。
Since WKWebView.evaluateJavaScript(_:) result is now async, this implementation solve a common requirement to have userAgent available in your own REST api call.
由于 WKWebView.evaluateJavaScript(_:) 结果现在是异步的,此实现解决了在您自己的 REST api 调用中提供 userAgent 的常见要求。
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
然后您可以访问该属性 UAString.userAgent
回答by gbk
Mobile application in every request must send his User-Agent
header with build version and device information
每个请求中的移动应用程序都必须发送User-Agent
带有构建版本和设备信息的标头
So, user agent should be like:
所以,用户代理应该是这样的:
User-Agent: <AppName>/version (<system-information>) <platform> (<platform-details>) <extensions>
User-Agent: <AppName>/version (<system-information>) <platform> (<platform-details>) <extensions>
For iOS:
对于 iOS:
User-Agent: <AppName/<version> (<iDevice platform>; <Apple model identifier>; iOS/<OS version>) CFNetwork/<version> Darwin/<version>
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
- 标题键 - 你可以硬编码或使用一些常量值
AppName 和版本 -从
Info.plist
let infoPlist = try? PListFile<InfoPlist>() let appName = infoPlist.data.bundleName let version = infoPlist.data.versionNumber let build = infoPlist.data.buildNumber
设备信息
modelName
- you can obtain like described here
modelName
- 你可以像这里描述的那样获得
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 }
CF网络版
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))) }
达尔文版
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
MyApp/1.8.199 (iOS; iPhone XS; 版本 13.3 (Build 17C45)) CFNetwork/1121.2.1 Darvin/19.3.0
回答by iAj
Swift 3.x, 4.x, 5.x, & above
Swift 3.x、4.x、5.x 及更高版本
As sometime traditional UIWebView get's memory leaked so instead use always WKWebView (far better from UIWebView)
由于有时传统的 UIWebView 会导致内存泄漏,因此始终使用 WKWebView(比 UIWebView 好得多)
import WebKit
var webViewForUserAgent: WKWebView?
and get userAgent by calling below function & you can also set it to your other variable
并通过调用下面的函数来获取 userAgent & 你也可以将它设置为你的其他变量
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")
}
}
}
回答by Jim Green
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:
在 iOS 中确定用户代理的一种更简单的方法是使用此 SO 帖子的公认答案直接从 UIWebView 获取它。但这种方式有两个缺点:
1、UIWebView 的第一次分配在初始化 webview 上下文时可能需要太多时间。
2、代码必须在主线程中执行。这可能会卡住主线程。
如果你知道如何在避免 App Store Review 拒绝的同时使用私有方法的技巧。
您可以尝试以下代码:
#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; }