如何在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:57:38  来源:igfitidea点击:

How to get the user agent on iOS?

iphoneios

提问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 UIWebViewusing 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-Agentheader with build version and device information

每个请求中的移动应用程序都必须发送User-Agent带有构建版本和设备信息的标头

User agent configuration info

用户代理配置信息

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?

如何获得每个组件?

  1. Headers Key - u can hardcode or use some constant values
  2. 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
    
  3. Info about Device

  1. 标题键 - 你可以硬编码或使用一些常量值
  2. AppName 和版本 -Info.plist

    let infoPlist = try? PListFile<InfoPlist>()
    let appName = infoPlist.data.bundleName
    let version = infoPlist.data.versionNumber
    let build = infoPlist.data.buildNumber
    
  3. 设备信息

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
  1. 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
    }
    
  1. 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
    }
    

from here

从这里

  1. 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)))
     }
    
  1. 达尔文版

     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)))
     }
    

from here

从这里

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")
        }
    }
}

enter image description here

在此处输入图片说明

回答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;
    }