2016-02-14 1 views
1

Я использую WKWebView и хочу получать уведомление, когда сайт полностью загружен. Метод webView:didFinishNavigationWKNavigationDelegate уволен, когда document.readyState либо interactive, либо complete, и я хочу быть уверенным, что сайт был полностью загружен. Я придумал решение, которое использует JavaScript-инъекцию. Вот мой MWE:ScriptMessageHandler не всегда вызывается на самом устройстве, отлично работает на симуляторе

import UIKit 
import WebKit 

class ViewController: UIViewController, WKScriptMessageHandler, WKNavigationDelegate { 

    var webView: WKWebView! 

    @IBOutlet weak var loadLabel: UILabel! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     let contentController = WKUserContentController() 

     let scriptPath = NSBundle.mainBundle().pathForResource("script", ofType: "js")! 
     let scriptString = try! String(contentsOfFile: scriptPath) 
     let script = WKUserScript(source: scriptString, injectionTime: .AtDocumentStart, forMainFrameOnly: true) 

     contentController.addUserScript(script) 
     contentController.addScriptMessageHandler(self, name: "readyHandler") 

     let configuration = WKWebViewConfiguration() 
     configuration.userContentController = contentController 

     webView = WKWebView(frame: CGRect.zero, configuration: configuration) 
     webView.navigationDelegate = self 
     loadLabel.text = nil 
    } 

    @IBAction func loadWebsite() { 
     webView.loadRequest(NSURLRequest(URL: NSURL(string: "http://stackoverflow.com")!)) 
     loadLabel.text = "Loading..." 
    } 

    func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) { 
     print("message received") 
     loadLabel.text = "Complete" 
    } 
} 

И это содержание script.js файла:

document.onreadystatechange = function() { 
    if(document.readyState === "complete"){ 
     webkit.messageHandlers.readyHandler.postMessage(""); 
    } 
} 

userContentController:didReceiveScriptMessage метод всегда вызывается на IOS Simulator, но и на реальном устройстве (iPhone 6 в моем случае) это не называется в большинстве случаев. Любая идея, что может быть неправильным в отношении этого или каким другим способом проверить, полностью ли загружен сайт?

+0

Does '.AtDocumentEnd' работает? – soflare

+0

@soflare На симуляторе, да, на устройстве, нет. Что более интересно, я тестировал его на другом устройстве (iPhone 5 с iOS 8.4.1), и он отлично работает. Таким образом, это похоже на проблему с самой iOS 9. –

+0

Убедитесь, что: 1. сценарий вставляется; 2. выполняется сценарий; 3. сообщение доставлено. Какой шаг нарушен? Попробуйте подключить webview с помощью Safari и изучить в консоли JS. – soflare

ответ

1

По какой-то причине вам необходимо добавить webView в видимое представление, чтобы это работало на устройстве. Если вы не хотите, чтобы webView был видимым, добавьте его, а затем установите для скрытого свойства значение true.

Для примера выше код:

func viewDidLoad(){ 
    ... 
    webView.hidden = true 
    view.addSubview(webView) 
} 
+0

К сожалению, невозможно добавить этот webView в какой-нибудь видимый контроллер представления. Мне нужна эта функциональность для фреймворка для экспорта веб-страниц в формате pdf. Я попытаюсь создать контроллер представления с webview, который я фактически не покажу пользователю. Я думаю, этот трюк - https://www.natashatherobot.com/ios-testing-view-controllers-swift/ - может работать здесь. –

+0

Я столкнулся с той же проблемой в своем проекте, где все звонки requireJS зависали. Как упоминалось в Xoogler, основной причиной является то, что веб-представление должно быть частью иерархии представлений до загрузки веб-сайта/страницы. Мой проект является основой, поэтому он не имеет закрывающего представления и не может добавить веб-представление в иерархию. Поэтому я должен изменить свой API, чтобы сообщить клиенту добавить веб-представление в иерархию, прежде чем загружать веб-контент. –

Смежные вопросы