IOS - 如何从 WKWebView 获取缓存资源?

标签 ios objective-c swift wkwebview

据我所知,WKWebView 中加载的所有资源的缓存是默认设置的。有几篇关于How to remove cached resources from WKWebView? 的帖子,但我找不到任何关于如何从 WKWebView 中获取它的帖子。

例如,当我使用WKWebView加载this url时,它显示一个 pdf 文件,我想要的是从 WKWebView 获取这个 pdf 文件,以便在 url 完全加载后共享

我在 Chrome 上检查过,如果我想从上面的链接共享文件,它会在显示共享对话框后再次从 url 请求和下载内容。这意味着他们无法从当前的 WKWebView(缓存的资源)中获取它。

但在 Safari 上,不知何故,他们在点击分享按钮后立即显示分享对话框,并且似乎没有再次下载。我认为他们从缓存或 WkWebView 中的某处获取 pdf 文件并共享它。

理解这个问题的另一种方法是How to get a file which presented on WKWebView without downloading content again?

enter image description here

如果问题没有足够的信息来回答,请随时发表评论,我会把它说得更清楚。

最佳答案

As I know, caching for the all resources loaded in WKWebView is set by default: True

请记住,如果您请求相同的资源,webview 将不会从 Internet 加载内容,它会为您提供缓存资源中的内容。对于请求相同的资源,您可以使用一些 JavaScript 来获取内容。

看下面的代码。加载 PDF 后,您点击保存按钮。它将执行 JavaScript 代码,当数据准备好通过 JavaScript 交付时

它将触发 window.webkit.messageHandlers.myInterface.postMessage(base64)

让您的 ViewController 知道数据已准备好共享。

您可以通过以下方式验证相同的内容

  1. 让它加载 PDF

  2. 关闭模拟器的网络(see)

  3. 点击保存按钮

您将获得 base64 格式的 pdf 数据。保存并分享:)

    import UIKit
    import WebKit
    class ViewController: UIViewController {

        @IBOutlet weak var webView: WKWebView!
        var activityIndicator: UIActivityIndicatorView?
        override func viewDidLoad() {
            super.viewDidLoad()

        }

        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
            webView.navigationDelegate = self
            activityIndicator?.center = self.view.center
            self.view.addSubview(activityIndicator!)
            webView.configuration.userContentController.add(self, name: "myInterface")
            webView.load(URLRequest(url: URL(string: "http://www.africau.edu/images/default/sample.pdf")!))
            activityIndicator?.startAnimating()
        }

        @IBAction func saveAction(_ 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) {
    //    print("Message received: \(message.name) with body: \(message.body)")

        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(documentsURL)

        let activityViewController = UIActivityViewController.init(activityItems: [documentsURL], applicationActivities: nil)
        present(activityViewController, animated: true, completion: nil)
      }
    }

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

顺便说一句,您提供的 pdf 链接使用的是 HTTP 而不是 HTTPS。因此,出于测试目的,请在您的 info.plist

中添加以下内容
<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoadsInWebContent</key>
        <true/>
    </dict>

关于IOS - 如何从 WKWebView 获取缓存资源?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50816070/

相关文章:

iOS UICircularProgressRing 径向渐变

objective-c - 防止来自 "PerformSelect may cause a leak because its selector is unknown"的警告

ios - 没有调用 Swift 函数?

ios - Xcode Storyboard 空间不足

ios - 每次我打开 View Controller 时都会获取聊天消息

ios - 如何立即知道内容已显示在 iOS 的 WebView 中

ios - Alamofire http json 请求 block ui

iphone - FileExistsAtPath 从 UIImagePickerController 返回 NO

ios - 设置 subview 比在 viewDidLoad 中更快

objective-c - 如何在 Xcode 4 中使用 "Turn On"版本编辑器?