如果无法访问 UIWebView 的运行时,为啥要在 iOS7 中使用 JavaScriptCore?

Posted

技术标签:

【中文标题】如果无法访问 UIWebView 的运行时,为啥要在 iOS7 中使用 JavaScriptCore?【英文标题】:Why use JavaScriptCore in iOS7 if it can't access a UIWebView's runtime?如果无法访问 UIWebView 的运行时,为什么要在 iOS7 中使用 JavaScriptCore? 【发布时间】:2013-09-20 15:31:33 【问题描述】:

这是对这篇博客的回应:

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

iOS 开发者对 SO 的看法?

【问题讨论】:

推荐这个库,可以用UIWebView轻松实现javascript和objc之间的通信:github.com/liaojinxing/HybridBridge 【参考方案1】:

你可以通过一个关键路径从 UIWebView 获取一个 JSContext:

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

Apple 从来没有记录任何新的 JavaScriptCore API,所以我不确定这是否算作内部/未记录的 API。我有一个批准使用此方法的应用。

更新:https://github.com/TomSwift/UIWebView-TS_JavaScriptContext 建议的另一种替代解决方案是在 NSObject 上创建一个类别,并使用它来实现 WebKit 记录的 didCreateJavaScriptContext 委托回调。套用这个实现,你可以调用 [NSObject contextForWebView:myWebView] 来获取 UIWebView 的 JSContext:

@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

【讨论】:

有没有其他人使用过这两种方法并让他们的应用被 Apple 接受? 如何发现 Web 视图上的关键路径?我在运行时标头中看到了一个 _documentView getter,但我很好奇有人比这更深入。【参考方案2】:

我想出了一种方法来获得与 KVC 方法不同的 UIWebView JSContext

基本上,通过了解 WebKit 的一些细节,我们可以在 NSObject 上实现一个委托回调方法,并在创建 JSContext 时将其交给它。详情在这里:

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

【讨论】:

优秀的代码示例。我不知道要调用这些方法,它们需要成为 JSExport 协议的一部分【参考方案3】:

这对于在应用程序中运行与 Web 无关的 JavaScript 很有用。想想您是否有一堆用 JavaScript 编写的现有代码,而您不想重新编写?您可以在没有 UIWebView 的情况下使用 JavaScriptCore 在您的流程中托管该代码。我还可以想象它被用来为 iOS 应用程序添加用户脚本功能。无限可能!

这里值得一提的另一件事是 UIWebView 非常需要资源(毕竟,这就像在您的进程中运行 Safari 的副本);它分配了大量的内存,您将永远无法取回。如果你不是特别需要网页渲染,JavaScriptCore 可以用更少的资源做很多事情。 UIWebView的资源消耗详见my answer over here。

【讨论】:

运行由用户贡献的任意 JS 脚本的能力是否会导致应用被应用商店拒绝? 我不是 AppStore 规则方面的专家,但我的理解是,如果用户输入它,那么你可以运行它,但你不能通过网络下载代码。有关此示例,请参阅 pythonforios.com。【参考方案4】:

您可以在 JavaScript 中实现应用程序逻辑,并在 iOS 和其他平台上使用 JS 代码。这减少了在 iOS、android、Web 等上支持应用程序的工作。

Calatrava 是围绕这个想法的一个框架。

【讨论】:

【参考方案5】:

您可以使用 JavaScript 编写 ios7 应用程序:

http://www.youtube.com/watch?v=y-nodF6Cp1Y

【讨论】:

别在意,我现在使用 JavaScript 执行此操作

以上是关于如果无法访问 UIWebView 的运行时,为啥要在 iOS7 中使用 JavaScriptCore?的主要内容,如果未能解决你的问题,请参考以下文章

uiwebview 阻止访问 uitoolbar 上的按钮

为啥 UIWebView 的 AVPlayerViewController 不在主线程上运行?

为啥 WKWebView 无法运行 processingjs 脚本?

将 UIWebView 设为公开

为啥Ubuntu系统无法运行VS Code

为啥js代码在HTML文件里可以运行,写在js文件里被html文件调用之后却是无法运行了?