代码之家  ›  专栏  ›  技术社区  ›  Nitesh

下载WKWebView中加载的嵌入式PDF

  •  7
  • Nitesh  · 技术社区  · 6 年前

    加载时 HTML5 从url获取页面我在该页面的某个位置获取pdf,我必须下载该pdf或将其另存为 base64 .

    这就是pdf在HTML代码中的位置。我不能简单地点击“src”URL获取pdf。

    < embed width="100%" height="100%" name="plugin" id="plugin" src="https://myurl.com/fileToOpen.pdf” type="application/pdf" internalinstanceid="8" title="">
    

    任何可以帮助我 基本64 字符串或任何其他下载方法?

    4 回复  |  直到 6 年前
        1
  •  4
  •   UdayaLakmal    4 年前

    这个问题有时会被问回来, 但是如果有人在找 敏捷的 解决方案 WKWebView 下载。pdf或文件管理器上的任何文件,我就是这样结束的

    class WebPortalVC: UIViewController, WKNavigationDelegate,WKUIDelegate, UIDocumentInteractionControllerDelegate,URLSessionDownloadDelegate {
    

    重写以下函数,该函数将拦截url,在我们的示例中,我们检查以结尾的ulr。pdf和。csv并重定向到使用文件管理器视图打开。支持查看文件、下载和保存设备存储、空投或与其他应用共享

    只需添加以下函数并进行检查。

     func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if let url = navigationAction.request.url {
    
            print("fileDownload: check ::  \(url)")
    
            let extention = "\(url)".suffix(4)
    
            if extention == ".pdf" ||  extention == ".csv"{
                print("fileDownload: redirect to download events. \(extention)")
                DispatchQueue.main.async {
                    self.downloadPDF(tempUrl: "\(url)")
                }
                decisionHandler(.cancel)
                return
            }
    
        }
    
        decisionHandler(.allow)
    }
    
    func downloadPDF(tempUrl:String){
        print("fileDownload: downloadPDF")
        guard let url = URL(string: tempUrl) else { return }
        let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())
        let downloadTask = urlSession.downloadTask(with: url)
        downloadTask.resume()
        //showHUD(isShowBackground: true); //show progress if you need
    }
    func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
        print("fileDownload: documentInteractionControllerViewControllerForPreview")
        return self
    }
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        // create destination URL with the original pdf name
        print("fileDownload: urlSession")
        guard let url = downloadTask.originalRequest?.url else { return }
        print("fileDownload: urlSession \(url)")
        let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let destinationURL = documentsPath.appendingPathComponent(url.lastPathComponent)
        // delete original copy
        try? FileManager.default.removeItem(at: destinationURL)
        // copy from temp to Document
        do {
            try FileManager.default.copyItem(at: location, to: destinationURL)
            myViewDocumentsmethod(PdfUrl:destinationURL)
            print("fileDownload: downloadLocation", destinationURL)
            DispatchQueue.main.async {
                NBMaterialToast.showWithText(self.view, text: "Download Completed", duration: NBLunchDuration.long)
            }
        } catch let error {
            print("fileDownload: error \(error.localizedDescription)")
        }
       // dismissHUD(isAnimated: false); //dismiss progress
    }
    func myViewDocumentsmethod(PdfUrl:URL){
        print("fileDownload: myViewDocumentsmethod \(PdfUrl)")
        DispatchQueue.main.async {
            let controladorDoc = UIDocumentInteractionController(url: PdfUrl)
            controladorDoc.delegate = self
            controladorDoc.presentPreview(animated: true)
        }
    }
    
        2
  •  3
  •   Sahil Manchanda    6 年前

    使现代化

    Docs 他们说

    Fetch API提供了一个用于获取资源的接口(包括 通过网络)。任何使用过 XMLHttpRequest

    您还可以使用以下字符串从WKWebview获取base64字符串

     let s = "path = document.getElementById(\"plugin\").src\n" +
            "\n" +
            "fetch(path).then(function (response) {\n" +
            " response.body.getReader().read().then(function(result) {\n" +
            " return btoa(String.fromCharCode.apply(null, result.value));\n" +
            " }).then(function(b64) {\n" +
            " window.webkit.messageHandlers.myInterface.postMessage(b64);\n" +
            " });\n" +
            "});"
    

    fetch和xmlhttp都是异步工作的。。您只需等待处理完成,然后使用javascript到ios的桥接器(WKScriptMessageHandler)将其传递给Swift

    使用以下代码 从javascript获取base64字符串到Swift . 我正在使用 WKScriptMessageHandler 从Javascript获取回调 当base64字符串准备好使用时 . 在字符串s中,您只需传递pdf的url,它将执行ajax请求以获取pdf文件,然后将其转换为base64字符串。

    import UIKit
    import WebKit
    class ViewController: UIViewController {
        @IBOutlet weak var btnPDF: UIButton!
        @IBOutlet weak var webViewParentView: UIView!
        var activityIndicator: UIActivityIndicatorView?
        var webView: WKWebView!
        @objc func didSelect(_ sender: UIView){
            let s="var xhr = new XMLHttpRequest();\n" +
                "xhr.open(\'GET\', \"https://codingexceptions.com/wkwebview/dummy.pdf\", true);\n" +
                "\n" +
                "xhr.responseType = \'arraybuffer\';\n" +
                "\n" +
                "xhr.onload = function(e) {\n" +
                " if (this.status == 200) {\n" +
                " var uInt8Array = new Uint8Array(this.response);\n" +
                " var i = uInt8Array.length;\n" +
                " var binaryString = new Array(i);\n" +
                " while (i--)\n" +
                " {\n" +
                " binaryString[i] = String.fromCharCode(uInt8Array[i]);\n" +
                " }\n" +
                " var data = binaryString.join(\'\');\n" +
                "\n" +
                " var base64 = window.btoa(data);\n" +
                "\n" +
                "window.webkit.messageHandlers.myInterface.postMessage(base64);" +
                "\n" +
                " }\n" +
                "};\n" +
                "\n" +
            "xhr.send();\n"
            webView.configuration.userContentController.add(self, name: "myInterface")
            webView?.evaluateJavaScript(s, completionHandler: {(string,error) in
                print(error ?? "no error")
            })
        }
        func setupWebView(){
            webView = WKWebView.init(frame: CGRect(x: 0, y: 0, width: webViewParentView.frame.width, height: webViewParentView.frame.height))
            webView.navigationDelegate = self
            webViewParentView.addSubview(webView)
            activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
            activityIndicator?.center = self.view.center
            self.view.addSubview(activityIndicator!)
            webView.load(URLRequest(url: URL(string: "https://codingexceptions.com/wkwebview/index.php")!))
            activityIndicator?.startAnimating()
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
            btnPDF.addTarget(self, action: #selector(self.didSelect(_:)), for: .touchUpInside)
    
        }
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
             setupWebView()
        }
    }
    extension ViewController: WKScriptMessageHandler{
        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
             print("Message received: \(message.name) with body: \(message.body)")
        }
    }
    extension ViewController: WKNavigationDelegate{
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            self.activityIndicator?.stopAnimating()
            self.activityIndicator?.removeFromSuperview()
            self.activityIndicator = nil
        }
    }
    

    更新:根据@Tarun的回答,从嵌入标记获取源代码

    只要把下面的 字符串变量s开头的行 并在xhr中传递url。打开

    var url = document.getElementById("plugin").src
    
        3
  •  2
  •   Tarun Lalwani    6 年前

    PS:使用答案作为注释,因为我需要格式化

    您应该在webview中执行以下JavaScript

    path = document.getElementById("plugin").src
    
    fetch(path).then(function (response) {
        response.body.getReader().read().then(function(result) {
            return btoa(String.fromCharCode.apply(null, result.value));
        }).then(function(b64) {
            window.pdf_data = b64;
        });
    });
    

    然后可以执行另一个查询来访问 window.pdf_data 假设可以从javascript执行中获取返回值?

        4
  •  -1
  •   ch1maera    6 年前

    您是否希望将PDF下载到iPhone或Mac?通常,无法将PDF直接下载到iPhone,因为iPhone本身没有存储PDF的功能。您需要有iBooks或iCloud Drive,然后在另一个窗口中打开PDF,然后手动下载。在下载PDF之前,仍然需要进行用户交互,这意味着用户必须批准下载。通过将JavaScript注入到 WKWebView 实例是不可能的。