WKWebView не завершил загрузку, когда вызывается функция FinishNavigation - ошибка в WKWebView?
Цель: сделать снимок экрана WKWebView после завершения загрузки сайта
Используемый метод:
- Определено WKWebView var в UIViewController
-
Создан метод расширения, называемый захватом экрана(), который принимает изображение WKWebView
-
Сделал мой UIViewController для реализации WKNavigationDelegate
-
Установите wkwebview.navigationDelegate = self (в инициализации UIViewController)
-
Реализована функция делегирования didFinishNavigation в UIViewcontroller для вызова метода расширения захвата экрана для WKWebView
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
let img = webView.screenCapture()
}
Вопросы:
- Когда я отлаживаю i-симулятор, я замечаю, что элемент управления достигает функции didFinishNavigation(), хотя веб-сайт еще не отображен в WKWebView
- Соответственно сделанный снимок экрана - это белый кадр.
Что мне здесь не хватает? Я просмотрел все возможные функции делегирования для WKWebView, и ничто иное не представляет собой завершение загрузки контента в WKWebView. Поблагодарите помощь, если есть работа вокруг
Обновление: добавление кода скриншота, который я использую, чтобы сделать снимок экрана для веб-представления
class func captureEntireUIWebViewImage(webView: WKWebView) -> UIImage? {
var webViewFrame = webView.scrollView.frame
if (webView.scrollView.contentSize != CGSize(width: 0,height: 0)){
webView.scrollView.frame = CGRectMake(webViewFrame.origin.x, webViewFrame.origin.y, webView.scrollView.contentSize.width, webView.scrollView.contentSize.height)
UIGraphicsBeginImageContextWithOptions(webView.scrollView.contentSize, webView.scrollView.opaque, 0)
webView.scrollView.layer.renderInContext(UIGraphicsGetCurrentContext())
var image:UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
webView.scrollView.frame = webViewFrame
return image
}
return nil
}
Ответы
Ответ 1
WKWebView не использует делегирование, чтобы вы знали, когда загрузка контента завершена (почему вы не можете найти какой-либо метод делегата, который соответствует вашей цели). Способ узнать, все еще загружается WKWebView, - использовать KVO (наблюдение за ключевыми значениями), чтобы посмотреть его свойство loading
. Таким образом вы получаете уведомление, когда loading
изменяется от true
до false
.
Вот циклический анимированный gif, показывающий, что происходит, когда я проверяю это. Я загружаю веб-представление и отвечаю на его свойство loading
через KVO, чтобы сделать снимок. Верхний вид - это веб-представление; нижний (сжатый) вид - это моментальный снимок. Как вы можете видеть, моментальный снимок захватывает загруженный контент:
![enter image description here]()
Ответ 2
Для тех, кто все еще ищет ответ на этот вопрос, отмеченный ответ - BS, он просто заставил его принять его. "загрузка" и webView (webView: WKWebView, didFinishNavigation navigation: WKNavigation!) делают то же самое, указывают, загружен ли основной ресурс. Теперь это не означает, что загружается вся веб-страница/веб-сайт, потому что это действительно зависит от реализации веб-сайта. Если вам нужно загрузить сценарии и ресурсы (изображения, шрифты и т.д.), Чтобы сделать себя видимыми, вы ничего не увидите после завершения навигации, потому что сетевые вызовы, сделанные веб-сайтом, не отслеживаются веб-просмотром, отслеживается, поэтому он не будет знать, когда сайт загружен полностью.
Ответ 3
Вот как я это решил:
class Myweb: WKWebView {
func setupWebView(link: String) {
let url = NSURL(string: link)
let request = NSURLRequest(URL: url!)
loadRequest(request)
addObserver(self, forKeyPath: "loading", options: .New, context: nil)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
guard let _ = object as? WKWebView else { return }
guard let keyPath = keyPath else { return }
guard let change = change else { return }
switch keyPath {
case "loading":
if let val = change[NSKeyValueChangeNewKey] as? Bool {
if val {
} else {
print(self.loading)
//do something!
}
}
default:break
}
}
deinit {
removeObserver(self, forKeyPath: "loading")
}
}
Обновить Swift 3.1
override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let _ = object as? WKWebView else { return }
guard let keyPath = keyPath else { return }
guard let change = change else { return }
switch keyPath {
case "loading":
if let val = change[NSKeyValueChangeKey.newKey] as? Bool {
//do something!
}
default:
break
}
}
Ответ 4
Много ручного отказа здесь, для неполных решений. Наблюдатель при "загрузке" не является надежным, потому что, когда он переключился на "НЕТ", макет еще не произошел, и вы не можете получить точное представление о размере страницы.
Внедрение JS в представление отчета о размере страницы также может быть проблематичным в зависимости от фактического содержимого страницы.
WKWebView использует, очевидно, скроллер (точнее, подкласс "WKWebScroller"). Поэтому лучше всего следить за этим скроллером contentSize.
- (void) viewDidLoad {
//...super etc
[self.webKitView.scrollView addObserver: self
forKeyPath: @"contentSize"
options: NSKeyValueObservingOptionNew
context: nil];
}
- (void) dealloc
{
// remove observer
[self.webKitView.scrollView removeObserver: self
forKeyPath: @"contentSize"];
}
- (void) observeValueForKeyPath: (NSString*) keyPath
ofObject: (id) object
change: (NSDictionary<NSKeyValueChangeKey,id>*) change
context: (void*) context
{
if ([keyPath isEqualToString: @"contentSize"])
{
UIScrollView* scroller = (id) object;
CGSize scrollFrame = scroller.contentSize;
NSLog(@"scrollFrame = {%@,%@}",
@(scrollFrame.width), @(scrollFrame.height));
}
}
Остерегайтесь contentSize: он запускается много. Если ваше веб-представление встроено в другую область прокрутки (например, если вы используете его в качестве элемента формы), то при прокрутке всего представления это веб-представление подпредставления вызовет изменения для тех же значений. Поэтому убедитесь, что вы не изменяете размеры без необходимости и не вызываете ненужных обновлений.
Это решение протестировано на iOS 12 на iPad Air 2 с симулятором High Sierra XCode 10.
Ответ 5
Не рекомендуется выбирать, загружено ли содержимое страницы с быстрой или objective-c особенно для очень сложной страницы со многими динамическими контентами.
Лучший способ сообщить вам код ios с веб-страницы javascript. Это делает его очень гибким и эффективным, вы можете уведомить ios-код, когда загружается dom или страница.
Здесь вы можете узнать мой пост.
Ответ 6
Поэтому ни один из этих ответов не работал у меня. Вот что работало.
Я использую webView как имя моего WKWebView. Переходите к тому, что вы использовали.
Я использовал Swift Spinner
Это создает великолепный полупрозрачный модальный надпись на всем экране. Загрузите его в viewDidLoad следующим образом:
SwiftSpinner.show("Doing something cool....")
Использование наблюдателя для остановки следующим образом:
Сначала добавьте это в свой метод webview... где вы загружаете свой URL-адрес:
webView?.addObserver(self, forKeyPath: #keyPath(WKWebView.loading), options: .new, context: nil)
Это используется для наблюдателя:
// To handle spinner stop; was testing other stuff, could simplify
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let wv = object as? WKWebView else {
return
}
guard let keyPath = keyPath else {
return
}
guard let change = change else {
return
}
print("in observer")
switch keyPath {
case "loading": // new:1 or 0
if let val = change[.newKey] as? Bool {
if val {
print("starting animating")
/// spinner.startAnimating()
} else {
if wv.estimatedProgress == 1 {
print("finished loading! stop animating spinner")
SwiftSpinner.hide()
}
}
}
default:
break