2015-09-18 6 views
11

Ich möchte einen Screenshot von einer WKWebView machen. Ich rufe die Methode drawViewHierarchyInRect (mit Bildschirmupdates auf true eingestellt) direkt nach dem Laden der Webansicht - zu diesem Zweck beobachte ich die loading Eigenschaft der Webansicht. Mir ist jedoch aufgefallen, dass zu dem Zeitpunkt, zu dem die Webansicht mich benachrichtigt, dass das Laden beendet ist, es sich nicht tatsächlich auf dem Bildschirm anzeigt. Deshalb ist der Screenshot immer nur weiß. Wenn ich den Screenshot 0,5 Sekunden nach dem Laden mache (was offensichtlich zu lang ist), zeigt der Screenshot das gewünschte Ergebnis. Mein Problem ist: Ich weiß nicht, wann die Webansicht tatsächlich auf dem Bildschirm angezeigt wird, ich könnte die Verzögerung wahrscheinlich auf 0,05 setzen, aber ich kann nicht 100% sicher sein, dass es jedes Mal funktioniert. Meine Frage lautet daher: Wie kann ich benachrichtigt werden, wenn die Web-Ansicht tatsächlich angezeigt wird und für einen Screenshot bereit ist?WKWebView Benachrichtigung, wenn die Ansicht tatsächlich angezeigt wird

Vielen Dank im Voraus!

BTW: Ich bin mit Swift 2.0 und iOS 9 mit Xcode 7 (official release)

Antwort

4

wie ich auf diese gerade gearbeitet haben, lassen Sie mich wissen, was ich versuchte, und wie ich es herausgefunden. Ich habe ein paar Dinge ausprobiert, zuerst einen WKUserScript auf dem Namespace "status". Diese wartet theoretisch für alle Inhalte geladen werden, und ruft dann die WKScriptMessageHandler

func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage){ } 

wenn über

registriert
wkwebView.configuration.userContentController.addScriptMessageHandler(self, name: "status") 

wo ich dachte, alles fertig sein würde. Arbeitete manchmal, aber nicht immer.

Wie Sie habe ich auch versucht, eine WKNavigationDelegate Zugabe und

func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) { } 

Wieder verwenden, dies funktionierte nicht. Auch das Hinzufügen eines Beobachters für den estimatedProgress Wert

wkwebView.addObserver(self, forKeyPath: "estimatedProgress", options: .New, context: nil) 

und dann den Screenshot zu machen versuchen, innerhalb

override func observeValueForKeyPath(keyPath: String?, ofObject: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) { } 

hat nicht funktioniert.

Wie funktioniert es jedoch, die Inhaltsgröße von webView regelmäßig zu überprüfen. Ich habe dies innerhalb der userContentController-Funktion getan, die vom WKUserScript aufgerufen wird - aber Sie können dies auch innerhalb der didFinishNavigation-Funktion tun und dann einfach die Funktion ändern, die erneut aufgerufen werden soll. Hier ist der Code:

let _contentSize = webview.scrollView.contentSize; 

if (_contentSize.height == 0){   
    dispatch_after(createDispatchTime(0.01), dispatch_get_main_queue()) { 
       self.userContentController(userContentController, didReceiveScriptMessage: message) 
    } 
    return 
} 

Dieser prüft im Wesentlichen auf der Höhe Content Eigenschaft und wenn es Null ist, wird es die Methode aufrufen, wieder alle 0,01 Sekunden, bis die Eigenschaft festgelegt ist. Hier sind die Funktionen, die ich für die Erstellung des Screenshots

var view : UIView! 

if self.useSnapShot { 
    // Use the snapshot function 
    view = webView.snapshotViewAfterScreenUpdates(true) 

} else { 
    // Draw the view as UIImage 
    UIGraphicsBeginImageContextWithOptions(webView.frame.size, false, 0.0) 
    webView.drawViewHierarchyInRect(webView.frame, afterScreenUpdates: true) 
    let snapshot = UIGraphicsGetImageFromCurrentImageContext() 
    view = UIImageView(image: snapshot) 
    view.frame = webView.frame 
} 

Ich habe es sowohl auf Gerät und Simulator getestet und es funktioniert.

bearbeiten

Hier kann die Funktion zum Erstellen der Versandzeitpunkt

private func createDispatchTime(seconds: Double) -> dispatch_time_t{ 
    let delay = seconds * Double(NSEC_PER_SEC) 
    return dispatch_time(DISPATCH_TIME_NOW, Int64(delay)) 
} 

Edit # 2

ich einen Kern geschaffen, die eine noch bessere Art und Weise zeigt, glaube ich https://gist.github.com/christopherhelf/1640454bcace39a87c93#file-wkwebviewplus-swift

Ich ersetzte die setContentSize-Funktion der UIScrollview von webviews und teilt der übergeordneten Klasse mit, dass eine Änderung vorgenommen wurde.

+0

Ich habe versucht, Ihre swizzle Methode Implementierung. Auch das wird gefeuert, bevor WebView tatsächlich für sehr schnelle Webseiten wie Wikipedia – shrutim

+0

rendert. Sie können auch die contentSize-Eigenschaft beobachten, anstatt eine verzögerte Funktion abzusetzen oder setContentSize zu überschreiben. Dies scheint bei der Erkennung von Größenänderungen zu funktionieren, aber es scheint auch in einem normalen Animationszyklus ausgelöst zu werden, obwohl es keine Änderung gibt. –

+0

Dies ist definitiv eine der besten Antworten. iOS WebView didFinishLoad wird aufgerufen, wenn Hauptinhalt geladen wird, aber iOS WebKit hat keine zuverlässigen Steuerelemente für Javascript. Das Problem steht hier. Der Hauptinhalt ist geladen, aber einige Javascript funktioniert immer noch (Laden, Umleiten von e.t.c) und WebKit wird nicht verfolgt. Die Lösung besteht darin, Steuerelemente auf JavaScript-Web-Inhalt und Call-Skript-Nachricht zu haben, wenn alle Daten geladen sind. Ich verwende dafür [https://github.com/marcuswestin/WebViewJavascriptBridge] (WebViewJavascriptBridge). – user2557885

Verwandte Themen