Change User Agent in UIWebView
Asked Answered
C

14

72

I have a business need to be able to customize the UserAgent for an embedded UIWebView. (For instance, I'd like the server to respond differently if, say, a user is using one version of the app versus another.)

Is it possible to customize the UserAgent in the existing UIWebView control the way it is, say, for an embedded IE browser in a Windows app?

Calm answered 25/1, 2009 at 21:57 Comment(0)
D
94

Modern Swift

Here's a suggestion for Swift 3+ projects from StackOverflow users PassKit and Kheldar:

UserDefaults.standard.register(defaults: ["UserAgent" : "Custom Agent"])

Source: https://mcmap.net/q/211869/-change-user-agent-in-uiwebview

Earlier Objective-C Answer

With iOS 5 changes, I recommend the following approach, originally from this StackOverflow question: UIWebView iOS5 changing user-agent as pointed out in an answer below. In comments on that page, it appears to work in 4.3 and earlier also.

Change the "UserAgent" default value by running this code once when your app starts:

NSDictionary *dictionary = @{@"UserAgent": @"Your user agent"};
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
[[NSUserDefaults standardUserDefaults] synchronize];

See previous edits on this post if you need methods that work in versions of iOS before 4.3/5.0. Note that because of the extensive edits, the following comments / other answers on this page may not make sense. This is a four year old question, after all. ;-)

Doggoned answered 25/1, 2009 at 21:58 Comment(12)
One downside to this approach: If your webView contains custom urls (someapplication://) they will fail since you're always returning YES.Poussette
@stigi try to change the key from @"User_Agent" to @"User-Agent". That worked for me.Pap
Anyone knows how to persist it through AJAX calls?Luanaluanda
@FelipeSabino - Try this technique instead? #8488081Doggoned
@LouisSt-Amour I see, the problem with this approach is that if I try to use my custom user agent, it set to any other web view I load after it, eg. the facebook SDK web view, which gets the layout broken if no default user agent is used.Luanaluanda
@LouisSt-Amour do you have any more information on using "User_Agent" -- why it works? Why it was necessary? Was there a bug in the platform?Gluteus
@Gluteus This was back in 3.x days. See my "2012 update" at the top of the post. And no, sorry, I can't say why it was necessary back then. It's possible that another layer in the TCP stack converts headers with underscores into headers with hyphens. All I can say is I think they've since fixed this behaviour, so I wouldn't worry about it.Doggoned
I'm trying this and it doesn't work, can you explain where is "when your app starts" I tried main.m , AppDelegate,didFinishLaunchingWithOptions and it doesn't work. This is probably different on iOS8Thaddeus
You should be able to place it anywhere before your webkit loads. Note that it's a bit of a "hammer" ... not always appropriate for every job and perhaps overkill... Example in swift: github.com/st3fan/WebKitExperiments/blob/…Doggoned
One important caveat here: this will modify the user-agent for all http requests generated by your app (at least those that are using the URL Loading System -- NSURLConnection and friends). This includes all UIWebViews in your app.Tugman
Could this be done initially in the controller for the web view? Like checking the url first and based on that call this [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary]; ? Basically I already tried but did not work out. Just want to know if it is even possible since you suggest to do this initially on startup.Mountainous
Umm. Not sure nowadays ... I bet there are other answers for the new iOS 7-based networking classes. This initial answer dates back to 2010-2012, I haven't needed it since. :)Doggoned
L
19

I had this problem too, and tried all methods. I found that only this method works (iOS 5.x): UIWebView iOS5 changing user-agent

The principle is to set the user agent permanently in the user settings. This works; Webview sends the given header. Just two lines of code:

NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"Mozilla/Whatever version 913.6.beta", @"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];

Setting User-Agent, or User_Agent in the mutable request, or overriding the setValue in the NSHttpRequest by swizzling, - I tried all that and controlled the results with wireshark, and none of that seems to work, because Webview still uses the user agent value from the user defaults, no matter what you try to set in the NSHttpRequest.

Loop answered 19/6, 2012 at 8:1 Comment(1)
Only this worked for me! you can now use a shorter version: [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"UserAgent": @"custom agent" }];Rainout
H
18

It should work with an NSMutableURLRequest as Kuso has written.

NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: @"http://www.google.com/"]];
[urlRequest setValue: @"iPhone" forHTTPHeaderField: @"User-Agent"]; // Or any other User-Agent value.

You'll have to use NSURLConnection to get the responseData. Set the responseData to your UIWebView and the webView should render:

[webView loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL];
Hosbein answered 17/2, 2009 at 21:16 Comment(1)
what would user agent string for safari on mac look like?Functionalism
A
12

Very simple in Swift. Just place the following into your App Delegate.

UserDefaults.standard.register(defaults: ["UserAgent" : "Custom Agent"])

If you want to append to the existing agent string then:

let userAgent = UIWebView().stringByEvaluatingJavaScript(from: "navigator.userAgent")! + " Custom Agent"
UserDefaults.standard.register(defaults: ["UserAgent" : userAgent])

Note: You may will need to uninstall and reinstall the App to avoid appending to the existing agent string.

Axiology answered 6/12, 2014 at 11:10 Comment(2)
Thanks. Saved lot of time!Joellajoelle
Thanks @Kheldar for updating for Swift 3. For earlier Swift versions check the edit history.Axiology
B
6

Taking everything this is how it was solved for me:

- (void)viewDidLoad {
    NSURL *url = [NSURL URLWithString: @"http://www.amazon.com"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setValue:@"Foobar/1.0" forHTTPHeaderField:@"User-Agent"];
    [webView loadRequest:request];
}

Thanks Everyone.

Blen answered 5/1, 2010 at 21:23 Comment(0)
N
6

Using @"User_Agent" simply causes a custom header to appear in the GET request.

User_agent: Foobar/1.0\r\n
User-Agent: Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Mobile/7D11\r\n

The above is what appears in the dissected HTTP packet, essentially confirming what Sfjava was quoting from that forum. It's interesting to note that "User-Agent" gets turned into "User_agent."

Nikko answered 12/1, 2010 at 20:39 Comment(0)
C
6

Actually adding any header field to the NSURLRequest argument in shouldStartLoadWithRequest seems to work, because the request responds to setValue:ForHTTPHeaderField - but it doesn't actually work - the request is sent out without the header.

So I used this workaround in shouldStartLoadWithRequest which just copies the given request to a new mutable request, and re-loads it. This does in fact modify the header which is sent out.

if ( [request valueForHTTPHeaderField:@"MyUserAgent"] == nil )
{
    NSMutableURLRequest *modRequest = [request mutableCopyWithZone:NULL];
    [modRequest setValue:@"myagent" forHTTPHeaderField:@"MyUserAgent"];
    [webViewArgument loadRequest:modRequest];
    return NO;
}

Unfortunately, this still doesn't allow overriding the user-agent http header, which is apparently overwritten by Apple. I guess for overriding it you would have to manage a NSURLConnection by yourself.

Collegiate answered 21/9, 2010 at 13:57 Comment(0)
J
5

By pooling the answer by Louis St-Amour and the NSUserDefaults+UnRegisterDefaults category from this question/answer, you can use the following methods to start and stop user-agent spoofing at any time while your app is running:

#define kUserAgentKey @"UserAgent"

- (void)startSpoofingUserAgent:(NSString *)userAgent {
    [[NSUserDefaults standardUserDefaults] registerDefaults:@{ kUserAgentKey : userAgent }];
}

- (void)stopSpoofingUserAgent {
    [[NSUserDefaults standardUserDefaults] unregisterDefaultForKey:kUserAgentKey];
}
Jujitsu answered 7/8, 2013 at 17:36 Comment(3)
tested in iOS7 on iPhone 5 device and it works, doesn't work on simulator but that doesnt' matter. thanks for the info.Englishman
startSpoofingUserAgent works for me however unregisterDefaultForKey is not a valid command. the only way I got this to work was to do a registerDefaults with the original value to reset it. -rrhBesotted
unregisterDefaultForKey: is implemented here: https://mcmap.net/q/212853/-how-can-i-remove-value-that-was-previously-registered-via-nsuserdefaults-registerdefaults-call (as noted in the answer).Jujitsu
R
4

This solution seems to have been seen as a pretty clever way to do it

changing-the-headers-for-uiwebkit-http-requests

It uses Method Swizzling and you can learn more about it on the CocoaDev page

Give it a look !

Rech answered 5/8, 2010 at 16:13 Comment(1)
Since iOS 5 the iOS no longer uses the public API to create its NSURLRequest objects anymore, so the swizzling method won’t work anymore under iOS 5.Hinkel
C
2

I faced the same question. I want to add some info to the user-agent, also need to keep the original user-agent of webview. I solved it by using the code below:

    //get the original user-agent of webview
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero];
NSString *oldAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
NSLog(@"old agent :%@", oldAgent);

//add my info to the new agent
NSString *newAgent = [oldAgent stringByAppendingString:@" Jiecao/2.4.7 ch_appstore"];
NSLog(@"new agent :%@", newAgent);

//regist the new agent
NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:newAgent, @"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary];

Use it before you instancing webview.

Corcoran answered 14/5, 2014 at 12:10 Comment(0)
D
1

Try this in the AppDelegate.m

+ (void)initialize 

{

    // Set user agent (the only problem is that we can’t modify the User-Agent later in the program)

    // iOS 5.1

    NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:@”Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B176 Safari/7534.48.3”, @”UserAgent”, nil];


    [[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary];

}
Dilan answered 17/1, 2013 at 12:28 Comment(0)
C
1

The only problem I have found was change user agent only

- (BOOL)application:(UIApplication *)application
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSDictionary *dictionary = [NSDictionary 
        dictionaryWithObjectsAndKeys:
        @"Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5", 
        @"UserAgent", nil];
    [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
}
Cari answered 8/2, 2013 at 12:10 Comment(0)
U
1

Apple will soon stop accepting apps with UIWebView. Find below for how you could change the user agent in WKWebView.

let config = WKWebViewConfiguration()

config.applicationNameForUserAgent = "My iOS app"

webView = WKWebView(frame: <the frame you need>, configuration: config)
Unrestraint answered 23/1, 2020 at 23:36 Comment(0)
L
0

To just add a custom content to the current UserAgent value, do the following:

1 - Get the user agent value from a NEW WEBVIEW

2 - Append the custom content to it

3 - Save the new value in a dictionary with the key UserAgent

4 - Save the dictionary in standardUserDefaults.

See the exemple below:

NSString *userAgentP1 = [[[UIWebView alloc] init] stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
NSString *userAgentP2 = @"My_custom_value";
NSString *userAgent = [NSString stringWithFormat:@"%@ %@", userAgentP1, userAgentP2];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:userAgent, @"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
Looselimbed answered 11/9, 2015 at 19:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.