WKWebViewで遭遇したピットを使用

5642 ワード

1.ios 9以前のバージョンでローカルHTMLを読み込んだ問題
loadRequestを使用してローカルのHTMLを読み込むと、WKWebViewは正常に読み込めません.バックグラウンドでは、Could not create a sandbox extension for /が表示されます.なぜなら、WKWebViewはローカルルートディレクトリのHTMLファイルをloadRequestでロードできないためです.iOS 9のSDKには、ローカルのHTMLファイルをロードする方法が追加されています.[WKWebView loadFileURL:allowingReadAccessToURL:]ですが、iOS 9以下のバージョンではこの便利な方法は提供されていません.iOS 9の次のバージョンでは、ローカルHTMLファイルのデータcopyをtmpディレクトリにコピーしてからloadRequestを使用してロードするソリューションを以下に示します.ただし、HTMLにjs、css、imageなどの他のリソースファイルが追加されている場合は、一緒にtempにコピーする必要があります.これは一番痛いことです.
解決策は以下の通り
1.Objective-C:
//   copy tmp  
- (NSURL *)fileURLForBuggyWKWebView8:(NSURL *)fileURL {
    NSError *error = nil;
    if (!fileURL.fileURL || ![fileURL checkResourceIsReachableAndReturnError:&error]) {
        return nil;
    }
    // Create "/temp/www" directory
    NSFileManager *fileManager= [NSFileManager defaultManager];
    NSURL *temDirURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:@"www"];
    [fileManager createDirectoryAtURL:temDirURL withIntermediateDirectories:YES attributes:nil error:&error];
    
    NSURL *dstURL = [temDirURL URLByAppendingPathComponent:fileURL.lastPathComponent];
    // Now copy given file to the temp directory
    [fileManager removeItemAtURL:dstURL error:&error];
    [fileManager copyItemAtURL:fileURL toURL:dstURL error:&error];
    // Files in "/temp/www" load flawlesly :)
    return dstURL;
}

//    
 NSString *path = [[NSBundle mainBundle] pathForResource:@"indexoff" ofType:@"html"];
    if(path){
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 9.0) {
            // iOS9. One year later things are OK.
            NSURL *fileURL = [NSURL fileURLWithPath:path];
            [self.webView loadFileURL:fileURL allowingReadAccessToURL:fileURL];
        } else {
            // iOS8. Things can be workaround-ed
            //   Brave people can do just this
            //   fileURL = try! pathForBuggyWKWebView8(fileURL)
            //   webView.loadRequest(NSURLRequest(URL: fileURL))
            
            NSURL *fileURL = [self.fileHelper fileURLForBuggyWKWebView8:[NSURL fileURLWithPath:path]];
            NSURLRequest *request = [NSURLRequest requestWithURL:fileURL];
            [self.webView loadRequest:request];
        }
    }

2.Swift
//   copy tmp  
func fileURLForBuggyWKWebView8(fileURL: NSURL) throws -> NSURL {
    // Some safety checks
    var error:NSError? = nil;
    if (!fileURL.fileURL || !fileURL.checkResourceIsReachableAndReturnError(&error)) {
        throw error ?? NSError(
            domain: "BuggyWKWebViewDomain",
            code: 1001,
            userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("URL must be a file URL.", comment:"")])
    }

    // Create "/temp/www" directory
    let fm = NSFileManager.defaultManager()
    let tmpDirURL = NSURL.fileURLWithPath(NSTemporaryDirectory()).URLByAppendingPathComponent("www")
    try! fm.createDirectoryAtURL(tmpDirURL, withIntermediateDirectories: true, attributes: nil)

    // Now copy given file to the temp directory
    let dstURL = tmpDirURL.URLByAppendingPathComponent(fileURL.lastPathComponent!)
    let _ = try? fileMgr.removeItemAtURL(dstURL)
    try! fm.copyItemAtURL(fileURL, toURL: dstURL)

    // Files in "/temp/www" load flawlesly :)
    return dstURL
}

//    

    var filePath = NSBundle.mainBundle().pathForResource("file", ofType: "pdf")

    if #available(iOS 9.0, *) {
        // iOS9. One year later things are OK.
        webView.loadFileURL(fileURL, allowingReadAccessToURL: fileURL)
    } else {
        // iOS8. Things can be workaround-ed
        //   Brave people can do just this
        //   fileURL = try! pathForBuggyWKWebView8(fileURL)
        //   webView.loadRequest(NSURLRequest(URL: fileURL))
        do {
            fileURL = try fileURLForBuggyWKWebView8(fileURL)
            webView.loadRequest(NSURLRequest(URL: fileURL))
        } catch let error as NSError {
            print("Error: " + error.debugDescription)
        }
    }

2.WKWebView-WKNavigationDelegate使用
特に、以下のdelegateの方法を使用する場合
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler

decisionHandlerのblockを実行する必要があります.
例:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    
    NSURLRequest *request = navigationAction.request;
    WMPageActionType actionType = ActionTypeNone;
    WKNavigationActionPolicy actionPolicy = WKNavigationActionPolicyAllow;
    if([request.URL.absoluteString hasPrefix:OC_CLOSE_REQUEST]){
        actionType = ActionTypeClose;
        actionPolicy = WKNavigationActionPolicyCancel;
    }
    if(self.actionDelegate && [self.actionDelegate respondsToSelector:@selector(webView:action:type:)]) {
        [self.actionDelegate webView:webView action:navigationAction type:actionType];
    }
   //        ,     
    decisionHandler(actionPolicy);
}

3.WKWebView-JS実行方法
WKWebView JSの実行方法はUIWebViewとは異なります.
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler;  

completionHandlerには2つのパラメータがあります.1つはエラーを返し、1つはスクリプトを実行した後の戻り値を返すことができます.