在用UIWebView的时候,如果访问需要http authentication,那么网页将无法显示。原因是UIWebView不会检测到网络设置,如代理设置,需要http认证等。
首先我们来说一下网络在代理环境中的authentication,如何让UIWebView正常工作。
由于UIWebView不会自动检测代理设置,所以解决方法是在UIWebViewDelegate方法中用NSURLConnect去连接到网络中任一网站,在NSURLConnectionDelegate接口中处理代理设置,在这儿需要代理用户名与密码。步骤如下:
1. 用NSURLConnect连接任一网站
- NSURLRequest *req = [NSURLRequest requestWithURL:url
- cachePolicy:NSURLRequestReloadIgnoringCacheData
- timeoutInterval:20.0];
- [[NSURLConnection alloc] initWithRequest:req delegate:self];
2. connection:didReceiveAuthenticationChallenge方法中处理代理设置
- - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
- {
- //如果是http代理,其它代理方法类似
- if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLProtectionSpaceHTTPProxy])
- {
- if ([challenge previousFailureCount] == 0) {
- /* SET YOUR credentials, i'm just hard coding them in, tweak as necessary */
- [[challenge sender] useCredential:[NSURLCredential credentialWithUser:AUTH_USERNAME password:AUTH_PASSWORD persistence:NSURLCredentialPersistencePermanent] forAuthenticationChallenge:challenge];
- } else {
- [[challenge sender] cancelAuthenticationChallenge:challenge];
- }
- }
- }
这下你的代理设置就保存了,因为用的是NSURLCredentialPersistencePermanent,以后在用UIWebView的时候就可以正常显示内容了。
更为完美的解决方案是NSURLProtocol参看:http://kadao.dir.bg/cocoa.htm
还有一种方法就是用ASIHttpRequest,开启
- request.shouldPresentProxyAuthenticationDialog = YES;
- [request setUseKeychainPersistence:YES];
这样detect到代理的时候就会弹出输入框加要用户输入用户名与密码,且保存在keychain里,下次运行不需要再输 。
接着我们来说一下如果网站需要http basic authentication,如何让UIWebView正常工作。
经过google我发现了下面这种方法:
需要http认证,其实就是在每次请求的时候需要在http头加入用户名与密码,保证这次请求的合法性。最开始的时候,我也是采用上面的方法,就是每次UIWebView开始请求的时候先用NSURLConnect去连接这个请求,在其 connection:didReceiveAuthenticationChallenge方法中处理用户名与密码。这种处理方法会两次访问同一个url且速度很慢。然后我就用了新的方法,即在NSURLRequest中加入Authorization字段,代码如下:
- NSURL *url = [NSURL URLWithString:yourUrlStr];
- NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
- NSString *authString = [[[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding] base64Encoding];
- authString = [NSString stringWithFormat: @"Basic %@", authString];
- [req setValue:authString forHTTPHeaderField:@"Authorization"];
其中username与password就是需要的用户名与密码。
网上有人写了一个NSMutableURLRequest的category,用起来也方便,随便也分享给大家。https://github.com/oscardelben/UIWebViewBasicAuth
在这儿我们得注意了:在头中加Authorization字段,我在iOS5中测试了, 通过这种方式request的UIWebView是不能成功显示网页的。没有iOS3与4测试,我猜测是以前的OS可以用这种方法。但是如果用NSURLConnection去request,这种方法是可行的,能返回正确的html,但是image这些不能显示。UIWebView是基于NSURL loading system的,理论上应是可行的,但是测试结果是不行。
即然这种方法不适用,那就得另寻方法。经过在网上找资料发现,如果把用户名与密码写在url里,那么就可以在UIWebView中正常访问。代码如下:
- NSString *URLString = [[NSString stringWithFormat:@"http://%@:%@@%@", @"username", @"password", [urlStr substringFromIndex:7]] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- NSURL *url = [NSURL URLWithString:URLString];
- NSURLRequest *req = [NSURLRequest requestWithURL:url
- cachePolicy:NSURLRequestReloadIgnoringCacheData
- timeoutInterval:20.0];
- webView loadRequest:req];
我在iPad1上测试可行,iPhone4上行,iPad与iPhone模拟器上都行,在iPad2上测试则不行,OS都是iOS5.
接在我在研究能通用方法,就是NSURL loading system。还在研究当中,有结果了再公布。
有了上面两种方法介绍,那么在有代理网络环境下去访问需要用户名与密码认识的网站,就可以完全正常了。
ASIWebPageRequest也是一个不错的选择,可以同时处理proxy与Http Basic Authentication。
参考:
http://www.springenwerk.com/2008/11/i-am-currently-building-iphone.html