Печать содержимого WKWebView (OS X)

Я пытаюсь распечатать содержимое 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? Предложения приветствуются. Благодарю вас.


person klaidazs    schedule 24.03.2015    source источник
comment
см. Как распечатать WKWebView в OSX и openradar.me/23649229   -  person l --marc l    schedule 02.09.2016


Ответы (3)


Решение, которое я использую, заключается в создании экземпляра старого доброго объекта 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)
        }
    }
}
person Ely    schedule 04.04.2018
comment
Ваш ответ для быстрого, а не для цели C - person soorej babu; 10.01.2019
comment
Хорошо спасибо. Пожалуйста, подумайте о невинных разработчиках Obj C, таких как я, в будущем - person soorej babu; 10.01.2019
comment
Обратите внимание, что при использовании этого примера кода вам необходимо сохранить класс, чтобы didFinishLoadFor работал. - person Tritonal; 16.06.2020

Если вашему приложению может потребоваться macOS 10.13 или более поздняя версия, в WKWebView есть новый метод: takeSnapshot(with:completionHandler:), который создает представление NSImage вашего веб-представления.

Насколько я знаю, это лучший вариант для рендеринга WKWebView в изображение.

person danielpunkass    schedule 14.12.2018
comment
Есть ли способ получить PDF (или хотя бы векторное представление) с помощью этого метода? - person AP.; 21.05.2019
comment
Я так не думаю. - person danielpunkass; 22.05.2019

Вы можете распечатать содержимое WKWebView с помощью viewPrintFormatter. Вот пример кода:

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");
    }];
}
person Imran Ali    schedule 17.04.2015
comment
UIPrintInteractionController НЕ доступен в OSX. Он доступен только на iOS. - person Cliff Ribaudo; 24.10.2015