Зачем использовать JavaScriptCore в iOS7, если он не может получить доступ к среде выполнения UIWebView?

Это в ответ на этот блог:

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

Мысли от разработчиков iOS на SO?

Ответы

Ответ 1

Вы можете получить JSContext из UIWebView с помощью ключевого пути:

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

Apple никогда не собиралась документировать какие-либо новые API JavaScriptCore, поэтому я не уверен, что это считается внутренним/недокументированным API или нет. У меня есть одобренное приложение, которое использует этот метод.

Обновление. Еще одно альтернативное решение, предложенное в https://github.com/TomSwift/UIWebView-TS_JavaScriptContext, - это сделать категорию на NSObject и использовать чтобы реализовать WebKit документированный ответный вызов делегата didCreateJavaScriptContext. Чтобы перефразировать эту реализацию, вы можете просто вызвать [NSObject contextForWebView:myWebView], чтобы захватить JSContext для 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

Ответ 2

Я придумал подход, чтобы получить UIWebView JSContext, который отличается от подхода KVC.

В принципе, зная некоторые подробности о WebKit, мы можем внедрить метод обратного вызова делегата в NSObject и передать его при создании. Подробности здесь:

https://github.com/TomSwift/UIWebView-TS_JavaScriptContext

Ответ 3

Это было бы полезно для запуска JavaScript, не связанного с веб-сайтом, размещенного внутри вашего приложения. Подумайте, есть ли у вас куча существующего кода, написанного на JavaScript, который вы не хотели переписывать? Вы можете использовать JavaScriptCore без UIWebView для размещения этого кода в вашем процессе. Я также могу предположить, что он используется для добавления пользовательской возможности для приложений iOS. Возможности бесконечны!

Еще одна вещь, о которой стоит упомянуть, заключается в том, что UIWebView очень ресурсоемкий (в конце концов, он вроде запускает копию Safari в вашем процессе); Он выделяет TON памяти, который вы просто никогда не вернетесь. Если вам не требуется веб-рендеринг, JavaScriptCore может многое сделать с гораздо меньшим количеством ресурсов. Подробнее о потреблении ресурсов UIWebView см. здесь.

Ответ 4

Вы можете реализовать логику приложения в JavaScript и использовать JS-код на iOS и других платформах. Это сокращает работу по поддержке приложения на iOS, Android, Web и т.д.

Calatrava является основой этой идеи.