This is in response to this blog:
http://blog.bignerdranch.com/3784-javascriptcore-and-ios-7/
Thoughts from the iOS devs on SO?
This is in response to this blog:
http://blog.bignerdranch.com/3784-javascriptcore-and-ios-7/
Thoughts from the iOS devs on SO?
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
I came up with an approach to get the UIWebView
JSContext
that is different from the KVC approach.
Basically, by knowing some details about WebKit, we can implement a delegate callback method on NSObject and be handed the JSContext when it is created. Details here:
It'd be useful for running non-web-related JavaScript hosted inside your application. Think about if you had a bunch of existing code written in JavaScript that you didn't want to re-write? You can use JavaScriptCore without a UIWebView to host that code in your process. I can also imagine it being used to add user-scriptability to iOS apps. The possibilities are endless!
The other thing worth mentioning here is that UIWebView is very resource-hungry (after all, it's like running a copy of Safari in your process); It allocates a TON of memory that you will simply never get back. If you don't specifically need web rendering, JavaScriptCore can do a lot with a lot fewer resources. See my answer over here for details about UIWebView's resource consumption.
You can write ios7 apps using JavaScript: