我试图直接将PDF加载到WKWebView中,而不向URL发出另一个直接请求。
在研究期间,我遇到了以下链接,该链接具有相同的作用。 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.
用于重现该问题的URL。 https://www.sciencedirect.com/science/article/pii/S0946672X17308763 只需访问“下载PDF”链接,然后在WKWebView中打开PDF。
编辑,用于在同一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提供的解决方案派生的完整快速代码,但是在代码片段中添加链接仍然存在一些问题。
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
}
}
答案 0 :(得分:1)
尝试在模拟器上执行以下代码。直接pdf链接不可用。它们动态生成pdf链接。因此,当页面加载完成时,它将具有最近的URL,并再次调用download方法,因此它将从缓存中保存。
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)
}
}
页面加载完成后。点击保存按钮。然后应打印如下内容:
查看网址 文件:///Users/jingged/Library/Developer/CoreSimulator/Devices/B57CEFE8-2A2A-484B-AB36-58E05B68EB1A/data/Containers/Data/Application/17317462-D36C-40EA-AEBD-0F128DC7E66A/Documents/sample.pdf
复制网址并粘贴到任何浏览器中。