UIWebView 使用URLProtocol解決
UIWebView的請求可以通過NSURLPtotol攔截,既可以攔截,也可以用本地的資源直接返回,可以實現資源本地化等各種需求,網上好多這種文章,所以此次不過多提及,主要針對WKWebView(僅考慮iOS11及以上,iOS11以下的網上也有,也是注冊私有方法)
WKWebView實現類似URLProtocol方法
通過繼承WKURLSchemeHandler的對象實現攔截
WKWebViewConfiguration類有如下方法:
image.png
可以讓我們通過自定義的協議去實現攔截,但是默認是不允許設置Http及Https以及FTP等請求的,所以需要我們自己修改一下(系統是否支持,需要我們自己
調用+[WKWebView handlesURLScheme:]來測試一下),
步驟如下:
1. WKWebViewConfiguration設置自定義WKURLSchemeHandler (有2種設置方式)
WKWebViewConfiguration *configuration = [WKWebViewConfiguration new];
CustomURLSchemeHandler *handler = [CustomURLSchemeHandler new];
//支持https和http的方法1 這個需要去hook +[WKwebview handlesURLScheme]的方法,可以去看WKWebView+Custome類的實現
[configuration setURLSchemeHandler:handler forURLScheme:@"https"];
[configuration setURLSchemeHandler:handler forURLScheme:@"http"];
//hook系統的方法2 xcode11可能會運行直接崩潰,因為用到了私有變量,xcode會檢測,但是xcode10沒問題,應該是xcode做了攔截,不影響使用
// NSMutableDictionary *handlers = [configuration valueForKey:@"_urlSchemeHandlers"];
// handlers[@"https"] = handler;//修改handler,將HTTP和HTTPS也一起攔截
// handlers[@"http"] = handler;
WKWebView *wk = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height-200) configuration:configuration];
[self.view addSubview:wk];
[wk loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.baidu.com"]]];
自己寫一個繼承WKURLSchemeHandler協議的對象
#import <WebKit/WebKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface CustomURLSchemeHandler : NSObject <WKURLSchemeHandler>
@end
NS_ASSUME_NONNULL_END
//這里攔截到URLScheme為customScheme的請求后,根據自己的需求,返回結果,并返回給WKWebView顯示
- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask{
NSURLRequest *request = urlSchemeTask.request;
NSLog(@"request = %@",request);
//如果是我們替對方去處理請求的時候
if (!manager) {
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
manager = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:config];
//這個acceptableContentTypes類型自己補充,demo不寫太多
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects: @"text/html", nil];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
}
NSURLSessionDataTask *task = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
[urlSchemeTask didReceiveResponse:response];
[urlSchemeTask didReceiveData:responseObject];
[urlSchemeTask didFinish];
}];
[task resume];
//如果是返回本地資源的話
// UIImage *image = [UIImage imageNamed:@"yang.jpg"];
// NSData *data = UIImageJPEGRepresentation(image, 1.0);
// NSURLResponse *response = [[NSURLResponse alloc] initWithURL:urlSchemeTask.request.URL MIMEType:@"image/jpeg" expectedContentLength:data.length textEncodingName:nil];
// [urlSchemeTask didReceiveResponse:response];
// [urlSchemeTask didReceiveData:data];
// [urlSchemeTask didFinish];
}
- (void)webView:(WKWebView *)webVie stopURLSchemeTask:(id)urlSchemeTask {
NSLog(@"stop = %@",urlSchemeTask);
}
@end
然后就可以實現攔截,以訪問的百度網頁為例,打印如下:
image.png
即可攔截或者替換本地資源