2016-05-29 3 views
1

私はSwiftに小さなiOSアプリケーションを構築しており、WKWebViewを使用しています。私が達成しようとしているのは、Webページが完全にレンダリングされたときに通知されることです。 WKWebViewの既知の問題で、ロード通知が機能しません。クリーナーはウェブページのwindow.onloadにフックする?

しかし、このアプローチはうまくいくように思えますが、その考え方はJavascriptのwindow.onload関数にフックしてそこからSwiftに通知することです。しかし、ここでも問題が見つかりました。 JQueryを使用すると、いくつかのページでは、Webページですでにwindow.onloadが定義されているため、コールバックは明らかに行われません。純粋なJavascriptの方法を使用している場合、一部のWebページが破損しています。つまり、window.onloadを上書きしているため、明らかにページが読み込まれません。

// using JQuery, this function never get called for web pages that do window.onload = 
$(window).load(function() { 
    window.webkit.messageHandlers.callbackHandler.postMessage(
     JSON.stringify({body: "window finished loading"})); 
}); 
// works always but breaks web pages that use window.onload 
window.onload = function() { 
    window.webkit.messageHandlers.callbackHandler.postMessage(
     JSON.stringify({body: "window finished loading"})); 
}; 

の質問はどのように私は、既存のwindow.onloadにこのライン通知を追加し、それが存在しない場合は1 window.onloadを定義することができますか?他のアイデアも歓迎します。キューイングwindow.load実装?

完全に私は、WKWebViewをネイティブに使用してそのような通知を得る2つの既知の方法を以下に示しました。

(1)ライフサイクル通知を取得しますが、Webページがまだ完全にレンダリングされていない場合、コールバック通知が早すぎます。

class ViewController: UIViewController { 
    // ... 
    func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) { 
     NSLog("didFinishNavigation callback received ... too early!") 
    } 
} 

(2)キー・バリューオブザーバー法(KVO)を使用しますが、ここで再び、コールバック通知は、あまりにも早すぎるトリガー:

webView.addObserver(viewController, forKeyPath: "estimatedProgress", options: .New, context: nil) 
// 
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<()>) { 
    guard let webView = object as? WKWebView else {return} 
    guard let change = change else {return} 
    guard let keyPath = keyPath else {return} 
    switch keyPath { 
     case "estimatedProgress": 
      if ((1.0 - webView.estimatedProgress) < 1e-10) { 
       NSLog("'estimatedProgress' callback received ... too early!") 
      } 
      break 
     default: break 
    } 
} 

それは「ロード」KVOで同じ問題です。

UPDATE:受け入れ答えに加えて、この他の質問running-jquery-after-all-other-js-has-executedにトップランクの答えは、例えば、ポーリングによってあまりにも特定の変更のためのDOMを、このOPを解決すべてのJavascriptがページの読み込みに加えて完了したとき。

+0

['$ $ {document} .ready(fn)'](https://learn.jquery。'fn'を渡した関数は、ページが準備できたら後で呼び出されます。ページの準備が整った後に別のレディ・ハンドラを追加すると、jqueryはすぐにレディ・コールバックを呼び出します。 – doug65536

+0

残念ながら、 '$(window).load(fn)'を使ったときと同じ問題があります。 –

+0

ありがとう!つまり、$(document).ready(fn)は$(window).load(fn)と同じ問題があります。 –

答えて

1

私はうまくいく方法を見つけました。しかし、重複する通知を避けるために、私の無益な試みにもかかわらず、私はまだ...代わりにあなたがDOMContentLoadedに耳を傾けることができイベントの

if (window.addEventListener) { 
    window.addEventListener("load", 
     function() { 
      // try to make sure it is called only once ... 
      if (typeof window.isMyiOSAppAlreadyNotified === 'undefined') { 
       // notify my iOS App that the page has finished loading 
       window.webkit.messageHandlers.callbackHandler.postMessage(
        JSON.stringify({body: "window onload"})); 
      } 
      window.isMyiOSAppAlreadyNotified = true; 
     } 
    ); 
} 
+0

jqueryドキュメントの準備が整ったら、他の答えのように 'DOMContentLoaded'が必要です。 'load'イベントは、すべてが完全にロードされた後に、ずっと後で発生します。ほとんどの場合、負荷がかかるまで待機する必要はありません。 – doug65536

+0

上記のObjective-CまたはSwiftをどのようにラップし、どのように呼び出すのかを示す完全なソリューションを提供できますか? – Dalmazio

3

をいくつかのWebページのための2つの通知を取得し、まだそれを修正する方法を発見していません。

また、あなたは、次の手順を実行して、実行スタックの最後にコールバックを実行することができます。

window.setTimeout(callback, 0); 

をさらにあなたのコールバックでremoveEventListenerを呼び出して試すことができます。例については

if (window.addEventListener) { 
    var documentIsReady = function() { 
     window.removeEventListener("load", documentIsReady); 

     if (typeof window.isMyiOSAppAlreadyNotified === 'undefined') { 
      window.webkit.messageHandlers.callbackHandler.postMessage(JSON.stringify({body: "window onload"})); 
     } 
     window.isMyiOSAppAlreadyNotified = true; 
    }; 
    window.addEventListener("load", function() { window.setTimeout(documentIsReady, 0); }); 
} 

あなたがmodule patternを適用することができますisMyiOSAppAlreadyNotifiedような変数とグローバル(ウィンドウ)のスコープを汚染避けるために。

+0

あなたの答えをありがとう!実際には、通知される可能性のある最新の時間に興味があります。つまり、「実行スタックの最後でコールバックを実行する」とすれば、これは完璧です。完全で自己完結型の回答を提供できますか?と私は受け入れるだろう,,, –

+0

完了、それが十分明確であるかどうか教えてください。 – Onato

+0

Objective-CまたはSwiftで上記を包み込む方法と、それを呼び出す方法を示す完全なソリューションを提供できますか? – Dalmazio

関連する問題