【问题标题】:Printing contents of WKWebView (OS X)WKWebView (OS X) 的打印内容
【发布时间】:2015-03-24 15:40:33
【问题描述】:

我正在尝试打印WkWebView 的内容,但是当打印面板出现时,打印预览为空。

代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];

    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    _webView = [[WKWebView alloc] initWithFrame:self.webViewOutlet.frame configuration:config];
    [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.google.com"]]];
    [_webViewOutlet addSubview:_webView];
    _webView.navigationDelegate = self;

}

我有一个WKWebView 的出口,所以我可以查看它是否已加载,我将print 调用放入didFinishNavigation 委托方法中,这样只是为了确定:

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
    [self.webView print:nil];
}

无论做什么页面,打印预览始终是空白页面。我还尝试使用NSPrintOperations,结果是一样的——打印预览和保存的 PDF 都是空白页。

任何想法我做错了什么?还有其他方法可以将WKWebView 打印/转换为 PDF 吗?欢迎提出建议。谢谢。

【问题讨论】:

标签: objective-c macos cocoa webkit wkwebview


【解决方案1】:

我使用的解决方案是实例化一个好的旧 WebView 对象,并使用该对象的打印方法。我的示例使用 html 字符串作为起点,但它应该很容易适应 URL。

目标 C

@interface WebPrinter ()
{
    WebView *printView;
    NSPrintInfo *printInfo;
}

@implementation WebPrinter

- (void)printHtml:(NSString *)html {

    if (!printInfo) {
        printInfo = [NSPrintInfo sharedPrintInfo];
        printInfo.topMargin = 25;
        printInfo.bottomMargin = 10;
        printInfo.rightMargin = 10;
        printInfo.leftMargin = 10;
    }

    NSRect printViewFrame = NSMakeRect(0, 0, printInfo.paperSize.width, printInfo.paperSize.height);
    printView = [[WebView alloc] initWithFrame:printViewFrame frameName:@"printFrame" groupName:@"printGroup"];
    printView.shouldUpdateWhileOffscreen = true;
    printView.frameLoadDelegate = self;
    [printView.mainFrame loadHTMLString:html baseURL:NSBundle.mainBundle.resourceURL];
}

- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {

    if (frame != sender.mainFrame) {
        return;
    }

    if (sender.isLoading) {
        return;
    }

    if ([[sender stringByEvaluatingJavaScriptFromString:@"document.readyState"] isEqualToString:@"complete"]) {

        sender.frameLoadDelegate = nil;

        NSWindow *window = NSApp.mainWindow;
        if (!window) {
            window = NSApp.windows.firstObject;
        }

        NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView: frame.frameView.documentView printInfo:printInfo];
        [printOperation runOperationModalForWindow:window delegate:window didRunSelector:nil contextInfo:nil];
    }
}

@end

斯威夫特

class WebPrinter: NSObject, WebFrameLoadDelegate {

    let window: NSWindow
    var printView: WebView?
    let printInfo = NSPrintInfo.shared

    init(window: NSWindow) {
        self.window = window
        printInfo.topMargin = 30
        printInfo.bottomMargin = 15
        printInfo.rightMargin = 0
        printInfo.leftMargin = 0
    }

    func printHtml(_ html: String) {
        let printViewFrame = NSMakeRect(0, 0, printInfo.paperSize.width, printInfo.paperSize.height)
        if let printView = WebView(frame: printViewFrame, frameName: "printFrame", groupName: "printGroup") {
            printView.shouldUpdateWhileOffscreen = true
            printView.frameLoadDelegate = self
            printView.mainFrame.loadHTMLString(html, baseURL: Bundle.main.resourceURL)
        }
    }

    func webView(_ sender: WebView!, didFinishLoadFor frame: WebFrame!) {
        if frame != sender.mainFrame {
            return
        }

        if sender.isLoading {
            return
        }

        if sender.stringByEvaluatingJavaScript(from: "document.readyState") == "complete" {
            sender.frameLoadDelegate = nil
            let printOperation = NSPrintOperation(view: frame.frameView.documentView, printInfo: printInfo)
            printOperation.runModal(for: window, delegate: window, didRun: nil, contextInfo: nil)
        }
    }
}

【讨论】:

  • 你的答案是 swift 而不是 Objective C
  • 好的,谢谢。以后请考虑像我这样无辜的 Obj C 开发者
  • 请注意,使用此示例代码时,您需要保留该类,didFinishLoadFor 才能工作。
【解决方案2】:

如果您的应用可能需要 macOS 10.13 或更高版本,WKWebView 上有一个新方法:takeSnapshot(with:completionHandler:),它会生成您的 Web 视图的 NSImage 表示。

据我所知,这是将 WKWebView 渲染为图像的最佳选择。

【讨论】:

  • 有没有办法使用这种方法获取 PDF(或至少是矢量表示)?
  • 我不这么认为。
【解决方案3】:

终于,Apple 似乎在 Swift 中对此有所作为。从 iOS 14 和 macOS 11 开始,您可以在 WKWebView 上使用 createPDF 将 HTML 文件的内容保存为 PDF。

https://developer.apple.com/documentation/webkit/wkwebview/3650490-createpdf

我刚刚在 Mac 应用程序(macOS 11.6 上的 Xcode 13)中尝试了它,并且成功了。

这是一个基本示例:

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
   
  webView.createPDF(){ result in
    switch result{
      case .success(let data):
        //Save the returned data to a PDF file
        try! data.write(to: URL(fileURLWithPath: "\(folder)/Cool.pdf"))

      case .failure(let error):
        print(error)
    }
  }
}

【讨论】:

    【解决方案4】:

    您可以使用viewPrintFormatter 打印WKWebView 的内容。 下面是示例代码:

    if ([UIPrintInteractionController isPrintingAvailable])
    {
        UIPrintInfo *pi = [UIPrintInfo printInfo];
        pi.outputType = UIPrintInfoOutputGeneral;
        pi.jobName = @"Print";
        pi.orientation = UIPrintInfoOrientationPortrait;
        pi.duplex = UIPrintInfoDuplexLongEdge;
    
        UIPrintInteractionController *pic = [UIPrintInteractionController sharedPrintController];
        pic.printInfo = pi;
        pic.showsPageRange = YES;
        pic.printFormatter = self.webView.viewPrintFormatter;
        [pic presentFromBarButtonItem:barButton animated:YES completionHandler:^(UIPrintInteractionController *printInteractionController, BOOL completed, NSError *error) {
            if(error)
                NSLog(@"handle error here");
            else
                NSLog(@"success");
        }];
    }
    

    【讨论】:

    • UIPrintInteractionController 在 OSX 上不可用。它仅适用于 iOS。
    • 如果从 iOS 或 macOS Catalyst 打印 WKWebView 效果很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多