【问题标题】:Download image from blob WKWebView without knowing the url在不知道 url 的情况下从 blob WKWebView 下载图像
【发布时间】:2019-03-25 23:51:32
【问题描述】:

我正在使用 WKWebView 访问一个网站,该网站上有一个下载按钮。在使用下载文件的笔记本电脑的 Chrome 上,当我在 iOS 模拟器上单击下载时,它会在 WKWebView 中显示图像。我的目标是保存该图像并稍后在 CollectionView 中显示它。如果我的 URL 为 https://www.website.com/image.jpg,那么这很容易做到,问题是它是一个 blob url,所以格式为 blob:https://www.website.com/abcd-efgh-ijkl

我发现这个链接有点帮助: How to read a blob data URL in WKWebView?

这是我的 ViewController 的精简版:

import UIKit
import WebKit

class DownloadBlob: UIViewController, WKNavigationDelegate, WKScriptMessageHandler {

    lazy var webView: WKWebView = {
        let config = WKWebViewConfiguration()
        config.userContentController.add(self, name: "readBlob")
        let webView = WKWebView(frame: UIScreen.main.bounds, configuration: config)
        webView.navigationDelegate = self
        return webView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        let request = URLRequest(url: url!)
        webView.load(request)
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("Finished")
    }

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

        decisionHandler(.allow)
    }

    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        print(navigationAction)
        let navigationURL = navigationAction.request.url
        if (navigationURL?.absoluteString.contains("blob"))! {
            testDownloadBlob(navigationURL: navigationURL!)
        }
        decisionHandler(.allow)
    }

    func testDownloadBlob(navigationURL: URL) {

        var script = ""
        script = script + "var xhr = new XMLHttpRequest();"
        script = script + "xhr.open('GET', '\(navigationURL.absoluteString)', true);"
        script = script + "xhr.responseType = 'blob';"
        script = script + "window.webkit.messageHandlers.readBlob.postMessage('making sure script called');"
        script = script + "xhr.onload = function(e) { if (this.status == 200) { var blob = this.response; window.webkit.messageHandlers.readBlob.postMessage(blob); var reader = new window.FileReader(); reader.readAsBinaryString(blob); reader.onloadend = function() { window.webkit.messageHandlers.readBlob.postMessage(reader.result); }}};"
        script = script + "xhr.send();"

        self.webView.evaluateJavaScript(script) { (results, error) in
            print(results ?? "")
        }
    }

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        print(message.name, message.body)
    }


}

我注意到 xhr.onload 根本没有被调用,但不知道如何解决这个问题。但是,我确实收到了与 decisionPolicyFor navigationResponse 中的 blob 相关的响应。

有没有办法获取图像数据并保存?

【问题讨论】:

  • 您找到解决方法了吗?
  • 找到解决方案了吗?

标签: javascript ios swift uiwebview wkwebview


【解决方案1】:

此链接有一个完整的解决方法,它也使用 datauri。重要的部分是使用 fetch 获取 blob 并转换为 datauri。 https://forums.developer.apple.com/thread/108394#333195
虽然,我看不出二进制字符串的 OP 的 postMessage 不起作用的任何原因。如果它确实有效,它将比使用需要转换为 base64 的数据 uri 更有效。
也许 OP 只是没有正确挂钩 Javascript 通信,或者 XHR 不起作用,必须使用 fetch。

下面只是将 Javascript 注入页面并通过拦截 blob 并使用 datauris 来使链接正常工作。 请注意,这是一个非常迂回的黑客攻击。扫描所有 href 并用 datauri 替换检测到的任何 blob url。 编辑:更新以显示它正在运行

function blobToDataURL(blob, callback) {
    var a = new FileReader();
    a.onload = function(e) {callback(e.target.result);}
    a.readAsDataURL(blob);
}
// not sure what elements you are going to intercept:
document.querySelectorAll('a').forEach(async (el)=>{
   const url = el.getAttribute('href');
   if( url.indexOf('blob:')===0 ) {
       let blob = await fetch(url).then(r => r.blob());
       blobToDataURL(blob, datauri => el.setAttribute('href',datauri));
   }
});

b=new Blob([new Int8Array([1,2,3,4,5,6,7,8,9,10]).buffer]);
test.href=URL.createObjectURL(b);
b=new Blob([new Int8Array([31,32,33,34,35]).buffer]);
test1.href=URL.createObjectURL(b);
b=new Blob([new Int8Array([51,52,53,54]).buffer]);
test2.href=URL.createObjectURL(b);



function blobToDataURL(blob, callback) {
    var a = new FileReader();
    a.onload = function(e) {callback(e.target.result);}
    a.readAsDataURL(blob);
}

document.addEventListener('click', function(event) {
  event.preventDefault();
  if ( event.target.matches('a[href^="blob:"]') )
     (async el=>{
       const url = el.href;
       const blob = await fetch(url).then(r => r.blob());
       blobToDataURL(blob, datauri => el.href=datauri);
     })(event.target);
});

// not sure what elements you are going to intercept:
/*document.querySelectorAll('a').forEach(async (el)=>{
   const url = el.href;
   if( url.indexOf('blob:')===0 ) {
       let blob = await fetch(url).then(r => r.blob());
       blobToDataURL(blob, datauri => el.href=datauri);
   }
});*/
<a id="test">test</a>
<a id="test1">test</a>
<a id="test2">test</a>

点击时数据uri转换示例:

b=new Blob([new Int8Array([1,2,3,4,5,6,7,8,9,10]).buffer]);
test.href=URL.createObjectURL(b);
b=new Blob([new Int8Array([31,32,33,34,35]).buffer]);
test1.href=URL.createObjectURL(b);
b=new Blob([new Int8Array([51,52,53,54]).buffer]);
test2.href=URL.createObjectURL(b);



function blobToDataURL(blob, callback) {
    var a = new FileReader();
    a.onload = function(e) {callback(e.target.result);}
    a.readAsDataURL(blob);
}

document.addEventListener('click', function(event) {
  if ( event.target.matches('a[href^="blob:"]') ) {
     event.preventDefault();
     (async el=>{
       const url = el.href;
       const blob = await fetch(url).then(r => r.blob());
       blobToDataURL(blob, datauri => window.open(el.href=datauri,el.target||'_self'));
     })(event.target);
   }
});

// not sure what elements you are going to intercept:
/*document.querySelectorAll('a').forEach(async (el)=>{
   const url = el.href;
   if( url.indexOf('blob:')===0 ) {
       let blob = await fetch(url).then(r => r.blob());
       blobToDataURL(blob, datauri => el.href=datauri);
   }
});*/
<a id="test">test</a>
<a id="test1">test</a>
<a id="test2">test</a>

【讨论】:

    猜你喜欢
    • 2016-06-16
    • 2016-03-25
    • 1970-01-01
    • 1970-01-01
    • 2015-07-31
    • 2013-04-03
    • 2015-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多