UIWebView JavaScript verliert Verweis auf iOS JSContext-Namespace (Objekt)

Ich habe an einer Proof-of-Concept-App gearbeitet, die die bidirektionale Kommunikation zwischen Objective C (iOS 7) und JavaScript mithilfe des WebKits nutztJavaScriptCore Rahmen. Ich konnte es endlich zum Funktionieren bringen, bin aber auf eine Situation gestoßen, in der die UIWebView ihren Verweis auf das iOS-Objekt verliert, das ich über JSContext erstellt habe.

Die App ist etwas komplex, hier sind die Grundlagen:

Ich verwende einen Webserver auf dem iOS-Gerät (CocoaHTTPServer).Das UIWebView lädt zunächst eine Remote-URL und wird später zurück zu umgeleitetlocalhost als Teil des App-Flows (denke an OAuth)Die HTML-Seite, die die App hostet (auf localhost), enthält das JavaScript, das mit meinem iOS-Code kommunizieren soll

Hier ist die iOS-Seite, die meines ViewControllers.h:

#import <UIKit/UIKit.h>
#import <JavaScriptCore/JavaScriptCore.h>

// These methods will be exposed to JS
@protocol DemoJSExports <JSExport>
-(void)jsLog:(NSString*)msg;
@end

@interface Demo : UIViewController <UserInfoJSExports, UIWebViewDelegate>
@property (nonatomic, readwrite, strong) JSContext *js;
@property (strong, nonatomic) IBOutlet UIWebView *webView;
@end

Und die relevanten Teile des ViewControllers.m:

-(void)viewDidLoad {
    [super viewDidLoad];

    // Retrieve and initialize our JS context
    NSLog(@"Initializing JavaScript context");
    self.js = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

    // Provide an object for JS to access our exported methods by
    self.js[@"ios"] = self;

    // Additional UIWebView setup done here...
}

// Allow JavaScript to log to the Xcode console
-(void)jsLog(str) {
    NSLog(@"JavaScript: %@", str);
}

Hier ist die (wegen dieser Frage vereinfachte) HTML / JS-Seite:

<html>
<head>
<title>Demo</title>
<script type="text/javascript">
    function setContent(c, noLog){
        with(document){
            open();
            write('<p>' + c + '</p>');
            close();
        }

        // Write content to Xcode console
        noLog || ios.jsLog(c);
    }    
</script>
</head>
<body onload="javascript:setContent('ios is: ' + typeof ios)">
</body>
</html>

Nun, in fast allen Fällen funktioniert das wunderbar, wie ich seheios is: object sowohl in der UIWebView als auch in der Xcode-Konsole. Sehr cool. In einem bestimmten Szenario schlägt dies jedoch in 100% der Fälle nach einer bestimmten Anzahl von Weiterleitungen in der UIWebView fehl, und sobald die obige Seite endlich geladen ist, heißt es:

ios ist: undefiniert

... und der Rest der JS-Logik wird wegen des nachfolgenden Aufrufs von beendetios.jsLog in demsetContent Funktion führt zu einer undefinierten Objektausnahme.

Also endlich meine Frage:Was könnte / kann dazu führen, dass ein JSContext verloren geht?? Ich habe die "Dokumentation" in den .h-Dateien von JavaScriptCore durchgesehen und festgestellt, dass dies nur möglich ist, wenn keine weiteren vorhanden sindstrong Verweise auf dieJSContext, aber in meinem Fall habe ich einen eigenen, also scheint das nicht richtig zu sein.

Meine einzige andere Hypothese ist, dass es mit der Art und Weise zu tun hat, in der ich das erworben habeJSContext Referenz:

 self.js = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];

Mir ist bewusst, dass diesmöglicherweise nicht offiziell von Apple unterstützt, obwohl ich mindestens einen SO'er gefunden habe, der angab, eine von Apple genehmigte App zu haben, die genau diese Methode verwendet.

BEARBEITEN

Ich sollte erwähnen, ich habe umgesetztUIWebViewDelegate So überprüfen Sie den JSContext nach jeder Umleitung in der UIWebView:

-(void)webViewDidFinishLoad:(UIWebView *)view{
    // Write to Xcode console via our JSContent - is it still valid?
    [self.js evaluateScript:@"ios.jsLog('Can see JS from obj c');"];
}

Dies funktioniert in jedem Fall, auch wenn meine Webseite endlich geladen und gemeldet wirdios is: undefined Die obige Methode schreibt gleichzeitigCan see JS from obj c zur Xcode Konsole. Dies scheint darauf hinzudeuten, dass der JSContext noch gültig ist und aus irgendeinem Grund in JS nicht mehr sichtbar ist.

Entschuldigung für die sehr langwierige Frage, es gibt so wenig Dokumentation darüber, dass ich dachte, je mehr Informationen ich liefern könnte, desto besser.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage