Why use JavaScriptCore in iOS7 if it can't access a UIWebView's runtime?

后端 未结 5 923
广开言路
广开言路 2020-12-23 17:55

This is in response to this blog:

http://blog.bignerdranch.com/3784-javascriptcore-and-ios-7/

Thoughts from the iOS devs on SO?

5条回答
  •  不知归路
    2020-12-23 18:54

    You can get a JSContext from a UIWebView with a key path:

    UIWebView *webView = [[UIWebView alloc] init];
    JSContext *ctx = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    ctx[@"document"][@"body"][@"style"][@"background"] = @"steelblue";
    

    Apple never got around to documenting any of the new JavaScriptCore APIs, so I'm not sure if this counts as an internal/undocumented API or not. I have an app approved that uses this method.

    Update: Another alternative solution suggested at https://github.com/TomSwift/UIWebView-TS_JavaScriptContext is to make a category on NSObject and use it to implement WebKit's documented didCreateJavaScriptContext delegate callback. To paraphrase that implementation, you can just call [NSObject contextForWebView:myWebView] to grab the JSContext for a UIWebView:

    @implementation NSObject(JSContextTracker)
    
    + (NSMapTable *)JSContextTrackerMap {
        static NSMapTable *contextTracker;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            contextTracker = [NSMapTable strongToWeakObjectsMapTable];
        });
        return contextTracker;
    }
    
    - (void)webView:(id)unused didCreateJavaScriptContext:(JSContext *)ctx forFrame:(id)alsoUnused {
        NSAssert([ctx isKindOfClass:[JSContext class]], @"bad context");
        if (!ctx)
            return;
        NSMapTable *map = [NSObject JSContextTrackerMap];
        static long contexts = 0;
        NSString *contextKey = [NSString stringWithFormat:@"jsctx_%@", @(contexts++)];
        [map setObject:ctx forKey:contextKey];
        ctx[@"JSContextTrackerMapKey"] = contextKey; // store the key to the map in the context itself
    }
    
    + (JSContext *)contextForWebView:(UIWebView *)webView {
        // this will trigger didCreateJavaScriptContext if it hasn't already been called
        NSString *contextKey = [webView stringByEvaluatingJavaScriptFromString:@"JSContextTrackerMapKey"];
        JSContext *ctx = [[NSObject JSContextTrackerMap] objectForKey:contextKey];
        return ctx;
    }
    
    @end
    

提交回复
热议问题