平時(shí)在打開某些網(wǎng)站時(shí),會(huì)提示不安全需要信任證書之類的提示,這些網(wǎng)頁(yè)要想在WKWebView上展示,還需要做一些適配
第一步
實(shí)現(xiàn)代理WKNavigationDelegate,找到如下方法,并實(shí)現(xiàn)
/*! @abstract Invoked when the web view needs to respond to an authentication challenge.
@param webView The web view that received the authentication challenge.
@param challenge The authentication challenge.
@param completionHandler The completion handler you must invoke to respond to the challenge. The
disposition argument is one of the constants of the enumerated type
NSURLSessionAuthChallengeDisposition. When disposition is NSURLSessionAuthChallengeUseCredential,
the credential argument is the credential to use, or nil to indicate continuing without a
credential.
@discussion If you do not implement this method, the web view will respond to the authentication challenge with the NSURLSessionAuthChallengeRejectProtectionSpace disposition.
*/
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
通過(guò)challenge.protectionSpace.authenticationMethod判斷信任方式,對(duì)應(yīng)的值為:
/*!
@const NSURLAuthenticationMethodClientCertificate
@abstract SSL Client certificate. Applies to any protocol.
*/
FOUNDATION_EXPORT NSString * const NSURLAuthenticationMethodClientCertificate API_AVAILABLE(macos(10.6), ios(3.0), watchos(2.0), tvos(9.0));
/*!
@const NSURLAuthenticationMethodServerTrust
@abstract SecTrustRef validation required. Applies to any protocol.
*/
FOUNDATION_EXPORT NSString * const NSURLAuthenticationMethodServerTrust API_AVAILABLE(macos(10.6), ios(3.0), watchos(2.0), tvos(9.0));
第二步,實(shí)現(xiàn)代理
實(shí)現(xiàn)如下代理便完成了服務(wù)端驗(yàn)證,沒有特殊需求實(shí)現(xiàn)如下方法頁(yè)面即可正常展示
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if ([self evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
}else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
}
#pragma mark 服務(wù)端驗(yàn)證
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain {
domain = nil;
/*
* 創(chuàng)建證書校驗(yàn)策略
*/
NSMutableArray *policies = [NSMutableArray array];
if (domain) {
[policies addObject:(__bridge_transfer id) SecPolicyCreateSSL(true, (__bridge CFStringRef) domain)];
} else {
[policies addObject:(__bridge_transfer id) SecPolicyCreateBasicX509()];
}
// 綁定校驗(yàn)策略到服務(wù)端的證書上
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef) policies);
// 評(píng)估當(dāng)前serverTrust是否可信任
SecTrustResultType result;
SecTrustEvaluate(serverTrust, &result);
if (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed) {
return YES;
}
return NO;
}
客戶端驗(yàn)證
添加客戶端驗(yàn)證的目的,主要還是覺得單向的服務(wù)端驗(yàn)證,不滿足項(xiàng)目需求,還需要加入客戶端驗(yàn)證,以保證項(xiàng)目的安全性,依項(xiàng)目實(shí)際需要使用即可
- (BOOL)clientCertificateTrust:(NSURLAuthenticationChallenge *)challenge{
SecTrustRef trust = challenge.protectionSpace.serverTrust;
SecTrustResultType result;
// 證書的路徑,此證書存放在項(xiàng)目目錄下
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"you" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData);
NSMutableArray *cerArray;
[cerArray addObject:(__bridge_transfer id)(certificate)];
SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)cerArray);
SecTrustSetAnchorCertificatesOnly(trust, false);
OSStatus status = SecTrustEvaluate(trust, &result);
if(status == errSecSuccess && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)){
return YES;
}
return NO;
}
使用中遇到的問(wèn)題
我個(gè)人在實(shí)際使用中遇到的問(wèn)題,就是WKWebview默認(rèn)緩存的問(wèn)題,在開了代理的情況下,有時(shí)候可以打開有時(shí)候不可以打開
解決方式也很簡(jiǎn)單,先判斷是否開啟代理:
+ (BOOL) getIsOpenProxy{
// 以任意網(wǎng)址校驗(yàn),是否開啟代理
NSURL *url = [[NSURL alloc] initWithString:@"http://www.baidu.com"];
NSDictionary *proxySettings = CFBridgingRelease(CFNetworkCopySystemProxySettings());
NSArray *proxies = CFBridgingRelease(CFNetworkCopyProxiesForURL((__bridge CFURLRef)url,
(__bridge CFDictionaryRef)proxySettings));
if (proxies.count > 0)
{
NSDictionary *settings = [proxies objectAtIndex:0];
NSString *host = [settings objectForKey:(NSString *)kCFProxyHostNameKey];
NSString *port = [settings objectForKey:(NSString *)kCFProxyPortNumberKey];
NSString *type = [settings objectForKey:(NSString *)kCFProxyTypeKey];
if (host || port || ![type isEqualToString:@"kCFProxyTypeNone"])
{
return YES;
}
}
return NO;
}
在加載的時(shí)候,使用不同的緩存策略:
NSMutableURLRequest *request;
if([Webtools getIsOpenProxy]){
// 開啟代理使用忽略本地緩存,直接從后臺(tái)獲取
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.requestURL] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15];
}else{
// 未開啟代理使用默認(rèn)緩存測(cè)試
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:self.requestURL] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15];
}