如何在iOS上获取用户代理?

时间:2011-12-20 16:56:26

标签: iphone ios

iOS上是否有办法获取设备的用户代理?我不想硬编码,因为我需要所有设备的用户代理,我需要将用户代理附加到URL。

感谢。

7 个答案:

答案 0 :(得分:39)

确定iOS中的用户代理的一种更简单的方法是使用this SO post的接受答案直接从UIWebView获取。引用这个答案:

  

解决方案是创建一个UIWebView,然后使用javascript来提取用户代理。

UIWebView* webView = [[UIWebView alloc] initWithFrame:CGRectZero];
NSString* secretAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];

答案 1 :(得分:4)

您实际上不需要发出请求以获取用户代理。只需从以下委托方法返回NO并保留user-Agent标头:

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

它可能看起来像这样:

-(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; 
}

答案 2 :(得分:4)

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

User agent configuration info

因此,用户代理应类似于:

User-Agent: <AppName>/version (<system-information>) <platform> (<platform-details>) <extensions>

对于iOS:

User-Agent: <AppName/<version> (<iDevice platform>; <Apple model identifier>; iOS/<OS version>) CFNetwork/<version> Darwin/<version>

如何获取每个组件?

  1. 标题键-您可以硬编码或使用some constant values
  2. AppName和版本-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. 有关设备的信息

modelName-您可以获得described here

    let modelName = UIDevice.current.modelName

其他组件:

    let platform = UIDevice.current.systemName
    let operationSystemVersion = ProcessInfo.processInfo.operatingSystemVersionString
  1. CFNetwork版本

    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. 达尔文版本

     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

结果:

MyApp / 1.8.199(iOS; iPhone XS;版本13.3(内部版本17C45))CFNetwork / 1121.2.1 Darvin / 19.3.0

答案 3 :(得分:0)

UIWebView已过时。在运行于iOS 8及更高版本的应用中,请使用WKWebView类,而不要使用UIWebView

// WKWebView
{
    WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
    [webView loadHTMLString:@"<html></html>" baseURL:nil];

    [webView evaluateJavaScript:@"navigator.appName" completionHandler:^(id __nullable appName, NSError * __nullable error) {
        NSLog(@"%@", appName);
        // Netscape
    }];

    [webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id __nullable userAgent, NSError * __nullable error) {
        NSLog(@"%@", userAgent);
        // iOS 8.3
        // Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12F70
        // iOS 9.0
        // Mozilla/5.0 (iPhone; CPU iPhone OS 9_0 like Mac OS X) AppleWebKit/601.1.32 (KHTML, like Gecko) Mobile/13A4254v
    }];

    // needs retain because `evaluateJavaScript:` is asynchronous
    self.webView = webView;
}

在此处了解更多-https://gist.github.com/Koze/cfda5d2af12f6215424e

答案 4 :(得分:0)

快速3.x,4.x,5.x及更高版本

由于有时传统UIWebView的内存泄漏,因此请始终使用WKWebView(远优于UIWebView)

import WebKit

var webViewForUserAgent: WKWebView?

并通过调用下面的函数获取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

答案 5 :(得分:0)

(iOS 8.0,*)

由于iOS 12中已弃用UIWebView,因此应改用WKWebView。

由于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 ?? ""
            }
        }
    }

}

现在最后一部分,您可以在初始视图控制器中实现此类,如下所示:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    UAString(view: self.view)
}

然后您可以以UAString.userAgent的身份访问该属性

答案 6 :(得分:-1)

在iOS中确定用户代理的一种更简单的方法是使用this SO post接受的答案直接从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;
    }