Уведомление WKWebView, когда на самом деле отображается представление

Я хочу сделать снимок экрана WKWebView. Я вызываю метод drawViewHierarchyInRect (с обновлениями экрана, установленным на true) сразу после завершения загрузки веб-представления - для этого я наблюдаю свойство loading веб-представления. Однако я заметил, что в то время, когда веб-представление уведомляет меня о завершении загрузки, оно фактически не отображается на экране. Вот почему скриншот всегда только белый. Когда я делаю снимок экрана через 0,5 секунды после загрузки (что явно слишком долго), снимок экрана показывает желаемый результат. Моя проблема: я не знаю, когда веб-представление фактически отображается на экране, я мог бы установить задержку на 0,05, возможно, но я не могу быть на 100% уверен, что он работает каждый раз. Поэтому мой вопрос: как я могу получить уведомление, когда на самом деле отображается веб-представление, он готов к скриншоту.

Спасибо заранее!

BTW: Я использую Swift 2.0 и iOS 9 с Xcode 7 (официальный выпуск)

Ответ 1

как я только что работал над этим, дайте мне знать, что я пытался и как я понял. Я попробовал пару вещей, во-первых, WKUserScript

let webViewUserScript = WKUserScript(
        source: "window.onload = function() { webkit.messageHandlers.status.postMessage(\(wkwebView.hashValue)) }",
        injectionTime: WKUserScriptInjectionTime.AtDocumentEnd,
        forMainFrameOnly: true
    )

в пространстве имен "status". Это теоретически ждет загрузки всего содержимого, а затем вызывает WKScriptMessageHandler

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

при регистрации через

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

где я думал, что все будет готово. Работал иногда, но не всегда.

Как вы, я также попытался добавить WKNavigationDelegate и использовать

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

Опять же, это не сработало. Кроме того, добавление наблюдателя для оценочного оценочного значения

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

а затем попытаться сделать снимок экрана в

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

не работает.

Однако работает ли проверка содержимого содержимого веб-контента на регулярной основе. Я сделал это в функции userContentController, которая вызывается WKUserScript, но вы также можете сделать это в функции didFinishNavigation, а затем просто изменить функцию, которая должна быть вызвана снова. Здесь код:

let _contentSize = webview.scrollView.contentSize;

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

Это существенно проверяет свойство contentSize height, и если оно равно нулю, он будет вызывать метод снова каждые 0.01 секунды, пока не будет установлено свойство. Вот функции, которые я использовал для создания скриншота

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
}

Я тестировал его как на устройстве, так и на симуляторе, и он работает.

Edit

Здесь функция создания времени отправки

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

Изменить # 2

Я создал суть, которая показывает еще лучший способ, которым я верю https://gist.github.com/christopherhelf/1640454bcace39a87c93#file-wkwebviewplus-swift

Я заменил функцию setContentSize веб-просмотров UIScrollview и уведомил родительский класс о том, что было сделано изменение.