前言
iOS开发过程中,有些页面是用H5进行开发,原生使用WebView
打开H5页面的链接,但是这种方式有一个很大的缺陷,就是打卡H5页面会很慢;因为H5页面一般都会引入各种各样的资源,有js
、css
、图片等等;这些资源在每一次打开H5页面的时候,会逐步通过网络请求下载到页面上,所以导致每一次打卡页面都比较慢;
那有没有一种办法处理呢?
那就是把这些资源进行缓存,只在第一次打开的时候,进行下载,并缓存到本地;后面再次打开的时候,就直接取缓存中的数据;
一、WKURLSchemeHandler介绍
WKURLSchemeHandler
是iOS11后开放出来的API,可通过WKURLSchemeHandler
检测到WKWebView
中的网络请求,通过原生进行处理;
二、WKURLSchemeHandler使用
1、WKWebview添加Catetory
#import <objc/runtime.h>
@implementation WKWebView(WIICustomer)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Method originalMethod1 = class_getClassMethod(self, @selector(handlesURLScheme:));
Method swizzledMethod1 = class_getClassMethod(self, @selector(bbhandlesURLScheme:));
method_exchangeImplementations(originalMethod1, swizzledMethod1);
});
}
+ (BOOL)bbhandlesURLScheme:(NSString *)urlScheme {
if ([urlScheme isEqualToString:@"http"] ||
[urlScheme isEqualToString:@"https"]) {
return NO; //这里让返回NO,不走系统断言,走自己的handler处理
} else {
return [self bbhandlesURLScheme:urlScheme];
}
}
@end
2、创建WKURLSchemeHandler类
class WIIWebViewSchemeHandler: NSObject & WKURLSchemeHandler {
public var module = "Test"
func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
guard let url = urlSchemeTask.request.url else {
urlSchemeTask.didFinish()
return
}
let urlPath = url.absoluteString
let key = urlPath.md5()
guard let localFilePath = self.getLocalFilePath(key: key) else {
urlSchemeTask.didFinish()
return
}
if FileManager.default.fileExists(atPath: localFilePath) {
let fileHandle = FileHandle(forReadingAtPath: localFilePath)
if let data = fileHandle?.readDataToEndOfFile() {
let mimeType = self.getMimeType(key: key)
let response = self.createURLResponse(url: url, data: data, mimeType: mimeType)
urlSchemeTask.didReceive(response)
urlSchemeTask.didReceive(data)
urlSchemeTask.didFinish()
try? fileHandle?.close()
return
}
try? fileHandle?.close()
}
let session = URLSession.shared
let task = session.dataTask(with: url) { data, response, err in
if let data = data, let response = response {
let mimeType = response.mimeType ?? "text/plain"
self.saveMimeType(mimeType, key: key)
let urlResponse = self.createURLResponse(url: url, data: data, mimeType: mimeType)
urlSchemeTask.didReceive(urlResponse)
urlSchemeTask.didReceive(data)
urlSchemeTask.didFinish()
try? data.write(to: URL(fileURLWithPath: localFilePath), options: Data.WritingOptions.atomic)
} else {
urlSchemeTask.didFailWithError(err ?? NSError())
}
}
task.resume()
}
func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
}
}
extension WIIWebViewSchemeHandler {
func createURLResponse(url: URL, data: Data, mimeType: String) -> URLResponse {
return URLResponse(url: url, mimeType: mimeType, expectedContentLength: data.count, textEncodingName: nil)
}
}
extension WIIWebViewSchemeHandler {
func getLocalFilePath(key: String) -> String? {
guard let rootPath = self.urlCacheRootFilePath() else {
return nil
}
return "\(rootPath)/\(key)"
}
func urlCacheRootFilePath() -> String? {
guard let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first else {
return nil
}
let directoryPath = "\(path)/\(self.module)"
if FileManager.default.fileExists(atPath: directoryPath) {
return directoryPath
}
try? FileManager.default.createDirectory(atPath: directoryPath, withIntermediateDirectories: true)
return directoryPath
}
}
extension WIIWebViewSchemeHandler {
func getMimeType(key: String) -> String {
return UserDefaults.standard.string(forKey: key) ?? ""
}
func saveMimeType(_ type: String, key: String) {
UserDefaults.standard.setValue(type, forKey: key)
}
}
3、WKWebView设置URLScheme
let config = WKWebViewConfiguration()
let handler = WIIWebViewSchemeHandler()
config.setURLSchemeHandler(handler, forURLScheme: "http")
config.setURLSchemeHandler(handler, forURLScheme: "https")
self.webview = WIIWebView(frame: self.view.bounds, configuration: config)