How to get the user agent on iOS?

后端 未结 6 2005
天涯浪人
天涯浪人 2020-12-14 19:59

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

相关标签:
6条回答
  • 2020-12-14 20:29

    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; 
    }
    
    0 讨论(0)
  • 2020-12-14 20:29

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

    0 讨论(0)
  • 2020-12-14 20:44

    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;
        }
    
    
    0 讨论(0)
  • 2020-12-14 20:48

    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"];
    
    0 讨论(0)
  • 2020-12-14 20:49

    Mobile application in every request must send his User-Agent header with build version and device information

    User agent configuration info

    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?

    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

    modelName - you can obtain like described here

        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
      }
      

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

    from here

    Result:

    MyApp/1.8.199 (iOS; iPhone XS; Version 13.3 (Build 17C45)) CFNetwork/1121.2.1 Darvin/19.3.0

    0 讨论(0)
  • 2020-12-14 20:50

    (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

    0 讨论(0)
提交回复
热议问题