iPhone/iPad – Get User-Agent for UIWebView

In each new version of iOS the browser gets a new user-agent string. I’ve been searching for a way to get the user-agent string from the API but haven’t been able to find a straight forward way to do it. Here’s my solution:

BSWebViewUserAgent.h

#import <Foundation/Foundation.h>
 
@interface BSWebViewUserAgent : NSObject <UIWebViewDelegate> {
	NSString *userAgent;
	UIWebView *webView;
}
@property (nonatomic, retain) NSString *userAgent;
-(NSString*)userAgentString;
@end

BSWebViewUserAgent.m

#import "BSWebViewUserAgent.h"
 
 
@implementation BSWebViewUserAgent
@synthesize userAgent;
 
-(NSString*)userAgentString
{
	webView = [[UIWebView alloc] init];
	webView.delegate = self;
	[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"www.google.com"]]];
 
	// Wait for the web view to load our bogus request and give us the secret user agent.
	while (self.userAgent == nil) 
	{
		// This executes another run loop. 
		[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
	}
 
	return self.userAgent;
}
 
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
	self.userAgent = [request valueForHTTPHeaderField:@"User-Agent"];
 
	// Return no, we don't care about executing an actual request.
	return NO;
}
 
- (void)dealloc 
{
	[webView release];
	[userAgent release];
	[super dealloc];
}
@end

I use a UIWebView, listen to its delegates and load a bogus URL. When shouldStartLoadWithRequest is called the supplied request contains the user-agent string in the header. Because UIWebView  loadRequest is asynchronous and we’re not really loading a request because we return NO in shouldStartLoadWithRequest there’s a loop waiting for the user-agent to be set. To wait for an asynchronous task to complete NSRunLoop is used. Each call to NSRunLoop runMode makes the application execute another loop, in this case executing the loadRequest call for our UIWebView.

Using the class is simple:

BSWebViewUserAgent *agent = [[BSWebViewUserAgent alloc] init];
NSLog(@"User-agent: %@", [agent userAgentString]);
[agent release];

This executes very fast, but if you have found an easier/faster way of extracting the user-agent, please let me know.

8 thoughts on “iPhone/iPad – Get User-Agent for UIWebView

  1. I should add that I store that string in the delegate once per startup, then I send it to my analytics tracker, (in my case Localytics) as a tagged event … that way I can update my served web pages back home.

  2. This is great; thanks for sharing it!

    I tried this and it hung for me when using URLWithString:@”www.google.com”. I changed it to a complete URL (URLWithString:@”http://www.example.com/” and all was well.

    @Greg Combs: Your one-liner will work great if you don’t mind getting the user agent after the fact. Björn’s technique is useful though if you want to retrieve the user agent ahead of time so you can, for example, tack on your own app’s identifier (which, I believe, is valid and correct behavior).

  3. @Trott

    In most cases you should definitely set your own user agent. However, sometimes you want to impersonate the real Safari browser user agent and avoid hard-coding the user agent into the app. Though, I have noticed that since writing this blog post the UIWebView will not always return the user agent of Safari. In some iOS versions they have differed slightly.

    // Björn

  4. You don’t actually need to make the request in order to get the user-agent. Just return NO from the delegate
    [code]
    -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    [code]

    method.

  5. Here is a 5 lines solution for those who want to MODIFY the user agent, not just replacing it. It uses a trick to retrieve the ORIGINAL user-agent string before modifying it. Useful if you want to add something at the end of it like here:
    [code]
    // Modify the user-agent
    NSString* suffixUA = @" iOSApp/1.0.1";
    UIWebView* webView = [[UIWebView alloc] initWithFrame:CGRectZero];
    NSString* defaultUA = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
    NSString* finalUA = [defaultUA stringByAppendingString:suffixUA];
    NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:finalUA, @"UserAgent", nil];
    [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
    [code]

    I spent an entire day trying to figure this one out! I'm sure it could be useful to other people.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>