直接从WKWebView获取已加载的PDF,而无需再次下载 [英] Get already loaded PDF directly from WKWebView without downloading again

查看:152
本文介绍了直接从WKWebView获取已加载的PDF,而无需再次下载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图直接将PDF加载到WKWebView中,而不向URL发出另一个直接请求.

I am trying to get PDF loaded in WKWebView directly without making another direct request to URL.

在研究期间,我遇到了以下链接,该链接具有相同的作用. IOS-如何从WKWebView获取缓存的资源?

During my research, I came across below link which does the same thing. IOS - How to get cached resources from WKWebView?

但是用这种方法,我在某些URL中遇到了问题. 我在控制台中遇到Javascript错误 Blocked script execution in 'https://ac.els-cdn.com/S0946672X17308763/1-s2.0-S0946672X17308763-main.pdf?_tid=8d087878-4e4c-4c50-b5e4-08ea38906e6e&download=true&acdnat=1534405212_984aaf5f9673f1b2ff107a4032c80ea0' because the document's frame is sandboxed and the 'allow-scripts' permission is not set.

but in that approach, I am getting an issue in some of the URLs. I am getting Javascript error in the console Blocked script execution in 'https://ac.els-cdn.com/S0946672X17308763/1-s2.0-S0946672X17308763-main.pdf?_tid=8d087878-4e4c-4c50-b5e4-08ea38906e6e&download=true&acdnat=1534405212_984aaf5f9673f1b2ff107a4032c80ea0' because the document's frame is sandboxed and the 'allow-scripts' permission is not set.

用于重现该问题的URL. https://www.sciencedirect.com/science/article/pii/S0946672X17308763 只需访问下载PDF"链接,然后在WKWebView中打开PDF.

URL to reproduce the issue. https://www.sciencedirect.com/science/article/pii/S0946672X17308763 Just visit in Download PDF link and open the PDF in WKWebView.

编辑,以便于在同一WebView中加载新的Tab窗口.

-(WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures{

    if (!navigationAction.targetFrame.isMainFrame) {
        [_webView loadRequest:navigationAction.request];
    }
    return nil;
}

编辑

我正在添加由@SahilManchanda提供的解决方案派生的完整的快速代码,但是在代码片段中添加的链接仍然存在一些问题.

I am adding complete swift code derived from the solution provided by @SahilManchanda but it still has some issue with link added in Code snippet.

import UIKit
import WebKit

class ViewController: UIViewController {

    var webView: WKWebView!
    var button: UIButton!
    let link = "https://www.sciencedirect.com/science/article/pii/S0946672X17308763"

    var activityIndicator: UIActivityIndicatorView?
    override func viewDidLoad() {
        super.viewDidLoad()

    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        webView = WKWebView()
        button = UIButton()
        button.setTitle("Save", for: .normal)
        button.setTitleColor(.white, for: .normal)
        button.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        button.addTarget(self, action: #selector(self.download(_:)), for: .touchUpInside)
        activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
        webView.navigationDelegate = self
        webView.uiDelegate = self
        activityIndicator?.center = self.view.center
        [webView,button].forEach({view.addSubview($0)})
        setupConstraints()
        webView.configuration.userContentController.add(self, name: "myInterface")
        webView.load(URLRequest(url: URL(string: link)!))
        activityIndicator?.startAnimating()
    }

    func setupConstraints(){
        webView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            webView.topAnchor.constraint(equalTo: view.topAnchor),
            webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
            ])
        button.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            button.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -70),
            button.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
            button.widthAnchor.constraint(equalToConstant: 100)
            ])
    }
    @objc func download(_ sender: Any){

        let s = """
        var xhr = new XMLHttpRequest();
        xhr.open('GET', "\(webView.url!.absoluteString)", true);
        xhr.responseType = 'arraybuffer';
        xhr.onload = function(e) {
        if (this.status == 200) {
        var uInt8Array = new Uint8Array(this.response);
        var i = uInt8Array.length;
        var binaryString = new Array(i);
        while (i--){
        binaryString[i] = String.fromCharCode(uInt8Array[i]);
        }
        var data = binaryString.join('');
        var base64 = window.btoa(data);

        window.webkit.messageHandlers.myInterface.postMessage(base64);
        }
        };
        xhr.send();
        """
        webView?.evaluateJavaScript(s, completionHandler: {(string,error) in
            print(error ?? "no error")
        })
    }
}
extension ViewController: WKScriptMessageHandler{
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        guard
            var documentsURL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last,
            let convertedData = Data.init(base64Encoded: message.body as! String)
            else {
                //handle error when getting documents URL
                return
        }
        //name your file however you prefer
        documentsURL.appendPathComponent("sample.pdf")
        do {
            try convertedData.write(to: documentsURL)
        } catch {
            //handle write error here
        }
        //if you want to get a quick output of where your
        //file was saved from the simulator on your machine
        //just print the documentsURL and go there in Finder
        print("URL for view \(documentsURL.absoluteString)")
        let activityViewController = UIActivityViewController.init(activityItems: [documentsURL], applicationActivities: nil)
        present(activityViewController, animated: true, completion: nil)
    }
}

extension ViewController: WKNavigationDelegate,WKUIDelegate{

    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {

        if !(navigationAction.targetFrame != nil && (navigationAction.targetFrame?.isMainFrame)!){
            webView .load(navigationAction.request);
        }

        return nil
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        self.activityIndicator?.stopAnimating()
        self.activityIndicator?.removeFromSuperview()
        self.activityIndicator = nil
    }
}

推荐答案

尝试在模拟器上执行以下代码.直接pdf链接不可用.它们动态生成pdf链接.因此,当页面加载完成时,它将具有最近的URL,并且再次调用download方法将因此从缓存中进行保存.

Try Following Code on simulator. The direct pdf links are not available. They generate the pdf link dynamically. So When the page gets finished loading it will have the recent url and calling the download method will request again and thus it will get saved from cache.

   import UIKit
import WebKit

class ViewController: UIViewController {

    var webView: WKWebView!
    var newWebView: WKWebView?
    let link = "https://www.sciencedirect.com/science/article/pii/S0946672X17308763"
    var d = false
    var activityIndicator: UIActivityIndicatorView?
    override func viewDidLoad() {
        super.viewDidLoad()

    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        webView = WKWebView()
        activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
        webView.navigationDelegate = self
        webView.uiDelegate = self
        activityIndicator?.center = self.view.center
        [webView].forEach({view.addSubview($0)})
        setupConstraints()
        webView.configuration.userContentController.add(self, name: "myInterface")
        webView.load(URLRequest(url: URL(string: link)!))
        activityIndicator?.startAnimating()
    }

    func setupConstraints(){
        webView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            webView.topAnchor.constraint(equalTo: view.topAnchor),
            webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
            ])
    }
    func download(_ sender: Any){
        guard let link = (sender as? URL)?.absoluteString else {return}
        print("\(link)")
        let s = """
        var xhr = new XMLHttpRequest();
        xhr.open('GET', "\(link)", true);
        xhr.responseType = 'arraybuffer';
        xhr.onload = function(e) {
        if (this.status == 200) {
        var uInt8Array = new Uint8Array(this.response);
        var i = uInt8Array.length;
        var binaryString = new Array(i);
        while (i--){
        binaryString[i] = String.fromCharCode(uInt8Array[i]);
        }
        var data = binaryString.join('');
        var base64 = window.btoa(data);

        window.webkit.messageHandlers.myInterface.postMessage(base64);
        }
        };
        xhr.send();
        """
        webView?.evaluateJavaScript(s, completionHandler: {(string,error) in
            print(error ?? "no error")
        })
    }
}
extension ViewController: WKScriptMessageHandler{
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        guard
            var documentsURL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last,
            let convertedData = Data.init(base64Encoded: message.body as! String)
            else {
                //handle error when getting documents URL
                return
        }
        //name your file however you prefer
        documentsURL.appendPathComponent("sample.pdf")
        do {
            try convertedData.write(to: documentsURL)
        } catch {
            //handle write error here
        }
        //if you want to get a quick output of where your
        //file was saved from the simulator on your machine
        //just print the documentsURL and go there in Finder
        print("URL for view \(documentsURL.absoluteString)")
        let activityViewController = UIActivityViewController.init(activityItems: [documentsURL], applicationActivities: nil)
        present(activityViewController, animated: true, completion: nil)
    }
}

extension ViewController: WKNavigationDelegate,WKUIDelegate{

    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {

        if !(navigationAction.targetFrame != nil && (navigationAction.targetFrame?.isMainFrame)!){
            webView .load(navigationAction.request);

        }

        return nil
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        self.activityIndicator?.stopAnimating()
        self.activityIndicator?.removeFromSuperview()
        self.activityIndicator = nil
        if d{
            download(webView.url)
        }
    }
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        print("url \(navigationAction.request.url!.absoluteString)")
        if navigationAction.request.url!.absoluteString.contains("pdfft"){
            if !d{
                d = true
                let url = navigationAction.request.url?.absoluteString.components(separatedBy: "?").first ?? ""
                decisionHandler(.cancel)
                webView.load(URLRequest(url: URL(string: url)!))
                return
            }

        }
        decisionHandler(.allow)
    }
}

页面加载完成后.点击保存按钮.然后应打印如下内容:

After Page finished loading. Click on the save button. It should then print something like below:

查看网址 文件:///Users/jingged/Library/Developer/CoreSimulator/Devices/B57CEFE8-2A2A-484B-AB36-58E05B68EB1A/data/Containers/Data/Application/17317462-D36C-40EA-AEBD-0F128DC7E66A/Documents/sample.pdf

URL for view file:///Users/jingged/Library/Developer/CoreSimulator/Devices/B57CEFE8-2A2A-484B-AB36-58E05B68EB1A/data/Containers/Data/Application/17317462-D36C-40EA-AEBD-0F128DC7E66A/Documents/sample.pdf

复制url并粘贴到任何浏览器中.

Copy the url and paste in any browser.

这篇关于直接从WKWebView获取已加载的PDF,而无需再次下载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆