WKWebVIew
OC:
HTTPS已经越来越被重视,前面我也写过一系列的HTTPS的相关文章HTTPS从原理到应用(四):iOS中HTTPS实际使用当加载一些HTTPS的页面的时候,如果此网站使用的根证书已经内置到了手机中这些HTTPS的链接可以正常的通过验证并正常加载。但是如果使用的证书(一般为自建证书)的根证书并没有内置到手机中,这时是链接是无法正常加载的,必须要做一个权限认证。开始在UIWebView的时候,是把请求存储下来然后使用NSURLConnection去重新发起请求,然后走NSURLConnection的权限认证通道,认证通过后,在使用UIWebView去加载这个请求。
在WKWebView中,WKNavigationDelegate中提供了一个权限认证的代理方法,这是权限认证更为便捷。代理方法如下:
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if ([challenge previousFailureCount] == 0) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
}
// Swift:
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
if challenge.previousFailureCount == 0 {
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
completionHandler(URLSession.AuthChallengeDisposition.useCredential,credential)
}else{
completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge,nil)
}
}else{
completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge,nil)
}
}
这个方法比原来UIWebView的认证简单的多。但是使用中却发现了一个很蛋疼的问题,iOS8系统下,自建证书的HTTPS链接,不调用此代理方法。查来查去,原来是一个bug,在iOS9中已经修复,这明显就是不管iOS8的情况了,而且此方法也没有标记在iOS9中使用,这点让我感到有点失望。这样我就又想到了换回原来UIWebView的权限认证方式,但是试来试去,发现也不能使用了。所以关于自建证书的HTTPS链接在iOS8下面使用WKWebView加载,我没有找到很好的办法去解决此问题。这样我不得已有些链接换回了HTTP,或者在iOS8下面在换回UIWebView。如果你有解决办法,也欢迎私信我,感激不尽。
UIWebView
//
// ViewController.m
// 02-HTTPS
#import "ViewController.h"
@interface ViewController ()<NSURLConnectionDelegate, UIWebViewDelegate>
{
NSURLRequest *_request;
}
@property (weak, nonatomic) IBOutlet UIWebView *webView;
@end
@implementation ViewController
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// NSString *str = [@"http://www.baidu.com" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *str = [@"https://kyfw.12306.cn/otn/leftTicket/init" stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
_request = request;
if ([str hasPrefix:@"https://"]) { // https请求先发送connection请求,就会安装证书
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];
NSLog(@"https请求");
}else{ // http请求直接加载
[self.webView loadRequest:request];
}
}
#pragma mark - NSURLConnectionDelegate 加载https网页,需要实现代理下面两个方法
/**
* 安装证书
*/
-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
/**
* 安装证书成功之后再加载https网页
*/
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)pResponse {
self.webView.scalesPageToFit = YES;
[self.webView loadRequest:_request];
}
/*
// 另一种方法加载https网页
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[self.webView loadRequest:_request];
}
*/
#pragma mark - UIWebViewDelegate
/*
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSLog(@"%@", request.URL);
return YES;
}
- (void)webViewDidStartLoad:(UIWebView *)webView
{
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error
{
}
*/
@end