【发布时间】:2014-03-09 23:27:49
【问题描述】:
我一直在开发一个概念验证应用程序,该应用程序利用 WebKit JavaScriptCore 框架在 Objective C (iOS 7) 和 JavaScript 之间进行双向通信。我终于能够让它按预期工作,但遇到了 UIWebView 失去对我通过 JSContext 创建的 iOS 对象的引用的情况。
该应用程序有点复杂,这里是基础知识:
- 我正在 iOS 设备上运行一个 Web 服务器 (CocoaHTTPServer)
- UIWebView 最初加载一个远程 URL,然后作为应用流程的一部分重定向回
localhost(想想 OAuth) - 应用托管的 HTML 页面(在本地主机上)包含应该与我的 iOS 代码对话的 JavaScript
这里是 iOS 端,我的 ViewController 的 .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
以及ViewController的.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);
}
这是(为了这个问题而简化的)HTML/JS 方面:
<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>
现在,在几乎所有情况下,这都很好,我在 UIWebView 和 Xcode 的控制台中都看到了ios is: object。很酷。但在一种特定情况下,100% 的情况下,在 UIWebView 中进行一定数量的重定向后,这会失败,并且一旦上述页面最终加载它就会说:
ios 是:未定义
...其余的 JS 逻辑退出,因为随后在 setContent 函数中调用 ios.jsLog 导致未定义对象异常。
最后我的问题是:什么可能/可能导致 JSContext 丢失?我翻阅了 JavaScriptCore 的 .h 文件中的“文档”,发现应该发生这种情况的唯一方法是,如果没有更多 strong 对 JSContext 的引用,但就我而言,我有自己的一个,所以这似乎不对。
我唯一的另一个假设是它与我获得JSContext 参考的方式有关:
self.js = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
我知道这个可能没有得到 Apple 的官方支持,尽管我确实找到了至少一个 SO'er 说他有一个 Apple 批准的应用程序使用了这种方法。
编辑
我应该提一下,我实现了UIWebViewDelegate,从而在 UIWebView 中的每次重定向后检查 JSContext:
-(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');"];
}
这适用于所有情况,即使我的网页最终加载并报告ios is: undefined,上述方法同时将Can see JS from obj c 写入Xcode 控制台。这似乎表明 JSContext 仍然有效,并且由于某种原因它不再从 JS 中可见。
对于这个冗长的问题,我深表歉意,我认为我可以提供的信息越多越好。
【问题讨论】:
-
嗨 Madbreaks,我有一个关于 JS 和 IOS 之间通信的问题。如果您有任何想法要解决,请告诉我。下面是我的链接“stackoverflow.com/questions/27120280/…”
标签: javascript ios objective-c uiwebview javascriptcore