Downloading files WKWebView ios

2019-03-16 21:07发布

I'm in the progress of migrating my app from UIWebView to WKWebView. All is going well and working as I tinker more with it. However, I notice now that I can't download forum attachments.

I'm using HCDownload, and thus far has always worked perfect for me, so I know it's not on that end. I believe its the request, but I cant figure it out.

I know the following:

UIWebView => WKWebView Equivalent
--------------------------------------------------------------
didFailLoadWithError => didFailNavigation
webViewDidFinishLoad => didFinishNavigation
webViewDidStartLoad => didStartProvisionalNavigation
shouldStartLoadWithRequest => decidePolicyForNavigationAction

So with that known I am trying below:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

    NSURLRequest *request = navigationAction.request;
    NSURL *fileURl = [request URL];
    NSString *externalFileExtension = [fileURl pathExtension];
    NSString *internalFileExtension = [[fileURl absoluteString] pathExtension];

    HCDownloadViewController *dlvc = [[HCDownloadViewController alloc] init];
    UINavigationController *vc = [[UINavigationController alloc] initWithRootViewController:dlvc];
    dlvc.delegate = self;
    vc.transitioningDelegate  = self;

    if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {

        //External file extensions
        if ([fileExtensions containsObject:[externalFileExtension lowercaseString]]) {
            [dlvc downloadURL:fileURl userInfo:nil];
            [self presentViewController:vc animated:YES completion:nil];
            [vc release];

            NSLog(@"externalURL is %@", fileURl);
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }

        //Internal file links
        if ([fileExtensions containsObject:[internalFileExtension lowercaseString]]) {
            [self presentViewController:vc animated:YES completion:nil];
            [dlvc downloadURL:fileURl userInfo:nil];
            [vc release];

            NSLog(@"internalURL is %@", fileURl);
            decisionHandler(WKNavigationActionPolicyCancel);
            return;

        }
}

It will fire my download controller by finding the file extension, but instead it downloads the index.php, not the file.

Example url:

https://example.com/index.php?app=core&module=attach&section=attach&attach_id=1234=example.zip;

What am I doing wrong. It worked fine before in UIWebView and I know things are done differently. But how can it download something from say dropbox just fine, but an attached file on a forum gets goofed up.

Any help would be appreciated

3条回答
混吃等死
2楼-- · 2019-03-16 21:44

Swift 4:

ChrisOSX's sollution also solved my issue. I'm trying to download a document from a link on a site after logging to that site. I've used WKZombie to scrape the link, and then I wanted to download the file using Alamofire. I added this

if let httpResponse = navigationResponse.response as? HTTPURLResponse, let url = httpResponse.url {
    let allHeaders = httpResponse.allHeaderFields.reduce([String : String](), { (result, next) -> [String : String] in
    guard let stringKey = next.key as? String, let stringValue = next.value as? String else { return result }
        var buffer = result
        buffer[stringKey] = stringValue
        return buffer
    })
    let cookies = HTTPCookie.cookies(withResponseHeaderFields: allHeaders, for: url)
    for cookie in cookies {
        HTTPCookieStorage.shared.setCookie(cookie)
    }
}

to:

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void)

After this, the cookies are stored in the shared cookies, and I was able to download the file with Alamofire without and changes to the download methods..

查看更多
在下西门庆
3楼-- · 2019-03-16 21:47

Well heres what I ended up with, and all seems to be working fine.

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
    NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
    for (NSHTTPCookie *cookie in cookies) {
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
    }

    decisionHandler(WKNavigationResponsePolicyAllow);
    //NSLog(@"decidePolicyForNavigationResponse");
}


//Download manager
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

    NSURLRequest *request = navigationAction.request;
    fileURL = request.URL;

    HCDownloadViewController *dlvc = [[HCDownloadViewController alloc] init];
    UINavigationController *vc = [[UINavigationController alloc] initWithRootViewController:dlvc];
    vc.transitioningDelegate  = self;
    dlvc.delegate = self;

    if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {

        //Internal file links
        NSString *internalFileExtension = fileURL.absoluteString.pathExtension;
        if ([fileExtensions containsObject:[internalFileExtension lowercaseString]]) {

            //Fire download
            [dlvc downloadURL:fileURL userInfo:nil];
            [self presentViewController:vc animated:YES completion:nil];
            [vc release];

            NSLog(@"internalURL is %@", fileURL);
            if (decisionHandler) {
                decisionHandler(WKNavigationActionPolicyCancel);
            }
            return;
        }

        //External file extensions
        NSString *externalFileExtension = fileURL.pathExtension;
        if ([fileExtensions containsObject:[externalFileExtension lowercaseString]]) {

            //Fire download
            [dlvc downloadURL:fileURL userInfo:nil];
            [self presentViewController:vc animated:YES completion:nil];
            [vc release];

            NSLog(@"externalURL is %@", fileURL);
            if (decisionHandler) {
                decisionHandler(WKNavigationActionPolicyCancel);
            }
            return;
        }
    }

    if (decisionHandler) {
        decisionHandler(WKNavigationActionPolicyAllow);
    }
}
查看更多
叛逆
4楼-- · 2019-03-16 21:49

You are probably downloading a not-authorized page because your WKWebView and HCDownload instances don't share cookie sessions like UIWebView could. That's a necessary trade-off for the WK2 process model's speed & security improvements.

I added downloading to my WKWebKit-based OSX/Swift mini-browser by implementing _WKDownloadDelegate. Its a totally undocumented private protocol as of El Cap and iOS9. It lets your navigation delegate call decisionHandler(_WKNavigationResponsePolicyBecomeDownload) whereby WebKit will download in the background after giving you the chance to pick/change a file name. I haven't the foggiest idea on how to implement a file picker in iOS yet, nor if using that protocol would be allowed by the App Store reviewers. But my app now does correctly handle downloading from session-authentication sites like your PHP forum.

查看更多
登录 后发表回答