在UIWebView中更改用户代理

72

我有一个业务需求,需要能够自定义嵌入式UIWebView的UserAgent。(例如,如果用户使用应用程序的某个版本与另一个版本不同时,我希望服务器有不同的响应。)

是否可以像Windows应用程序中的嵌入式IE浏览器一样,以现有的UIWebView控件的方式自定义UserAgent呢?

14个回答

95

现代的Swift

以下是来自StackOverflow用户PassKit和Kheldar的关于Swift 3+项目的建议:

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

来源: https://dev59.com/LHRB5IYBdhLWcg3w4bKv#27330998

早期的Objective-C回答

随着iOS 5的变化,我建议采用以下方法,最初来自这个StackOverflow问题:UIWebView iOS5 changing user-agent,如下面的一个答案所指出。在该页面的评论中,它似乎也适用于4.3和更早版本。

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];

如果您需要适用于iOS 4.3/5.0之前版本的方法,请查看此帖子的先前编辑。请注意,由于进行了广泛的编辑,此页面上的以下评论/其他答案可能没有意义。毕竟,这是一个四年前的问题。;-)


6
尝试将关键字从@"User_Agent"更改为@"User-Agent"。这对我有效。 - William Niu
1
@nmr 这是在3.x时代。请看我在帖子顶部的“2012更新”。不好意思,我不能说为什么那时候需要这样做。可能是TCP堆栈中的另一层将带下划线的标头转换为带连字符的标头。我只能说我认为他们已经修复了这个问题,所以不用担心它。 - Louis St-Amour
这里有一个重要的警告:这将修改您的应用程序生成的所有HTTP请求的用户代理(至少是使用URL加载系统 - NSURLConnection和相关组件的请求)。这包括您的应用程序中的所有UIWebView。 - noamtm
1
这个能否最初在Web视图的控制器中完成呢? 比如先检查URL,然后根据它调用 [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary]; ? 基本上我已经尝试过了,但没有成功。只是想知道是否可能,因为您建议在启动时最初执行此操作。 - Pedroinpeace
现在不太确定...我敢打赌,对于基于新iOS 7的网络类,还有其他答案。这个最初的答案可以追溯到2010-2012年,自那以后我就再也没有需要它了。 :) - Louis St-Amour
显示剩余7条评论

19

我也遇到了这个问题,并尝试了所有方法。我发现只有这种方法有效(iOS 5.x):UIWebView iOS5 changing user-agent

原理是在用户设置中永久设置用户代理。这行得通;Webview会发送给定的标头。只需两行代码:

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

我尝试过设置User-Agent,或在可变请求中设置User_Agent,或通过swizzling覆盖NSHttpRequest中的setValue方法,用wireshark控制结果,但所有这些似乎都不起作用,因为Webview仍然使用用户默认值中的user agent值,无论你在NSHttpRequest中尝试设置什么。


2
只有这个对我起作用!现在你可以使用一个更短的版本:[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"UserAgent": @"custom agent" }]; - Yariv Nissim

18

如Kuso所写,它应该可以与NSMutableURLRequest一起使用。

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

您需要使用 NSURLConnection 获取 responseData。将 responseData 设置为您的 UIWebView,webView 就应该可以渲染:

[webView loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL];

Safari在Mac上的用户代理字符串会是什么样子? - AceN

12

在Swift中非常简单。只需将以下内容放入您的App Delegate中。

UserDefaults.standard.register(defaults: ["UserAgent" : "Custom Agent"])
如果您想要追加到现有的代理字符串中,则:

如果您想要追加到现有的代理字符串中,则:

let userAgent = UIWebView().stringByEvaluatingJavaScript(from: "navigator.userAgent")! + " Custom Agent"
UserDefaults.standard.register(defaults: ["UserAgent" : userAgent])
注意:您可能需要卸载并重新安装该应用程序,以避免将信息添加到现有的代理字符串中。

谢谢。节省了很多时间! - KD.
感谢@Kheldar更新至Swift 3。对于早期的Swift版本,请查看编辑历史记录。 - PassKit

6

根据我的解决方案,所有问题都已得到解决:

- (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.


6
使用@"User_Agent"只会导致自定义头部在GET请求中出现。
以下是HTTP数据包的解析结果,基本上证实了Sfjava从那个论坛引用的内容。有趣的是,“User-Agent”被转换为“User_agent”。

6

实际上,在shouldStartLoadWithRequest中向NSURLRequest参数添加任何头字段似乎是有效的,因为请求会响应setValue:ForHTTPHeaderField - 但它实际上不起作用 - 请求在没有头部的情况下被发送出去。

因此,我在shouldStartLoadWithRequest中使用了这个解决方法,它只是将给定的请求复制到一个新的可变请求中,并重新加载它。这确实修改了要发送的头部。

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

很遗憾,这仍然不能覆盖用户代理 http 标头,因为它被苹果覆盖了。我想如果要覆盖它,你将不得不自己管理 NSURLConnection。


5

1
已在iPhone 5设备上的iOS7中进行了测试,可以正常工作。虽然在模拟器上无法运行,但这并不重要。感谢提供信息。 - New2ObjectiveC
startSpoofingUserAgent 对我有效,但 unregisterDefaultForKey 不是一个有效的命令。我让它起作用的唯一方法是使用原始值进行 registerDefaults 以重置它。-rrh - Richie Hyatt
unregisterDefaultForKey: 在这里实现:https://dev59.com/VlDTa4cB1Zd3GeqPIVzb#18109860(如答案中所述)。 - EthanB

4

2
自从iOS 5以后,iOS不再使用公共API来创建其NSURLRequest对象,因此在iOS 5下,交换方法将不再起作用。 - Mike Keskinov

2

我曾经遇到过同样的问题。我想要向用户代理中添加一些信息,同时需要保留webview的原始用户代理。我通过使用以下代码来解决这个问题:

    //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];

在实例化Webview之前使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接