2016-07-09 20 views
1

Ich möchte die Async-Funktionalität von WKWebView außerhalb der Webansicht angeboten verwenden. Die JS-Kontextoption stellt die Async-Funktionalität nicht bereit.Async-Kommunikation von Swift und Javascriptcore

In WKWebView, schreibe ich meine Logik wie folgt.

func swiftFunc1() { 
    webView.evaluateJavaScript("jsFunc1(), completionHandler: nil) 
} 

In Javascript Code, den ich eine Nachricht an schnellen

function jsFunc1() { 
    window.webkit.messageHandlers.myMsg.postMessage("call swiftFunc2"); 
} 

Der SWIFT-Code kann dann den Umgang Nachricht entsprechenden JS Rückruf als Teil nennen.

Aber das hängt davon ab, dass das Webview die Vordergrundansicht ist. Wenn ich die JS-Logik unabhängig von der Webansicht verwenden möchte, ist JSContext die Option. Ich versuchte folgende

func swiftFunc1() { 
    myCtxt = JSContext() 
    exportedToJS = exportToJS() //confirms to JSExport and uses @objc 
    myCtxt.setObject(exportedToJS.self, forKeyedSubscript: "swiftIface") 
    myFunc = myCtxt.objectForKeyedSubscript("jsFunc1") 
    myFunc.callWithArguments(nil) 
} 

Jetzt in Javascript-Code kann ich keine Nachricht an swift. Wenn ich versuche, eine schnelle Funktion wie folgt aufzurufen, bleibt der Code für immer hängen.

function jsFunc1() { 
    swiftIface.swiftFunc2() // This creates a deadklock 
} 

Wie kann ich eine der folgenden ohne „Rückkehr“ von der gerufenen Javascript-Funktion jsFunc1() erreichen?

  1. Entweder eine Nachricht an swift veröffentlichen, so dass es

  2. entsprechende Maßnahmen ergreifen können Oder eine schnelle Funktion aufrufen, so dass die entsprechenden Maßnahmen ergriffen werden

Antwort

0

Habe ich Sie richtig verstehe, Wenn Sie nicht möchten, dass Ihr javscript nach der Ausführung beendet wird?

Wenn ich dich falsch verstanden habe, hilft vielleicht folgende (ich bin nicht zu Hause bei Mac zu testen, aber vielleicht funktioniert es, wenn Sie Ihren Code wie folgt ändern).

Option 1:

func swiftFunc1() { 
    myCtxt = JSContext() 
    myCtxt.setObject(unsafeBitCast(swiftFunc2, AnyObject.self), forKeyedSubscript: "swiftFunc2") 
    exportedToJS = exportToJS() //confirms to JSExport and uses @objc 
    myCtxt.evaluateScript("swiftFunc2()") 
} 

Ihre swiftFunc2 wie folgt aussehen würde:

let swiftFunc2: @convention(block) Void -> Void = { 
    // do something here 
} 

Ihre JS Code wie folgt aussehen würde Blocks

Die swiftFunc1 könnte wie folgt aussehen:

function jsFunc1() { 
    swiftFunc2(); 
} 

Option 2: JSExport Sie haben eine exportierte Klasse, die für alle zugänglich ist Javascript:

import Foundation 
import JavaScriptCore 
@objc class JavascriptHandler: NSObject, JavascriptHandlerExport { 
    let context: JSContext = JSContext() 

    init() { 
    context.setObject(self, forKeyedSubscript: "MyJSHandler") // set the object name for self accessible in javascript code 
    } 
    func swiftFunc1() { 
    context.evaluateScript("MyJSHandler.swiftFunc2();") 
    } 
    func swiftFunc2() { 
    // do something here 
    } 
} 

Ihr Protokoll für die exportierte class.Here Sie mögen, dass Sie alle Eigenschaften und Methoden erklären müssen verwenden, um mit Javascript.

Damit sollte es Ihnen möglich sein, eine Funktion von Javascript aufzurufen und trotzdem weiterlaufen zu lassen. Sie jetzt die Funktionen der Klasse JavascriptHandler von Javascript wie dies in diesem Beispiel zugreifen:

MyJSHandler.swiftFunc2(); 

Wenn Sie die Klasse trennen wollen, wo Ihre WebView von dem ist, wo Ihre JS Logik liegt das sollte auch kein Problem sein. Sie sollten auch in der Lage sein, die Block-Syntax mit der JSExport-Methode zu kombinieren.

Lassen Sie mich wissen, wenn es nicht funktioniert/wie gewünscht verhält.

+0

Danke für die Antwort. Aber bedeutet das, dass ich nur Blöcke/Schließungen benutzen sollte, um das zu umgehen? JSExport kann diese Art von Aufrufsequenz nicht verarbeiten, oder? – Amruta

+0

Es sollte auch mit JSExport möglich sein. Vielleicht, wenn ich morgen Zeit habe, kann ich versuchen, ein Beispiel zu geben. – snailmensch

+0

Ich freue mich darauf! – Amruta