Mad*_*aks 18 javascript objective-c uiwebview ios javascriptcore
我一直在研究一个概念验证应用程序,它利用WebKit JavaScriptCore框架利用Objective C(iOS 7)和JavaScript之间的双向通信.我终于能够按预期工作了,但是遇到了UIWebView失去对我通过JSContext创建的iOS对象的引用的情况.
该应用程序有点复杂,以下是基础知识:
localhost作为应用程序流的一部分(想想OAuth)这是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
Run Code Online (Sandbox Code Playgroud)
以及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);
}
Run Code Online (Sandbox Code Playgroud)
这是(为了这个问题而简化)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>
Run Code Online (Sandbox Code Playgroud)
现在,在几乎所有情况下,这ios is: object都很好用,我在UIWebView和Xcode的控制台中都看到了.很酷.但是在一个特定的场景中,100%的时间,在UIWebView中的一定数量的重定向后失败,并且一旦上面的页面最终加载它就说:
ios是:undefined
...和JS逻辑的其余部分退出,因为后续调用ios.jsLog中setContent的一个未定义的对象除外功能的结果.
最后我的问题是:什么可能/可能导致JSContext丢失?我挖掘了JavaScriptCore的.h文件中的"文档",发现这应该发生的唯一方法是,如果没有更多的strong引用JSContext,但在我的情况下,我有一个我自己的,所以这不似乎是对的.
我唯一的另一个假设是它与我获取JSContext参考的方式有关:
self.js = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
Run Code Online (Sandbox Code Playgroud)
我知道这可能不会得到Apple的正式支持,尽管我确实发现至少有一个SO'er表示他有一个苹果认可的应用程序使用了这种方法.
编辑
我应该提一下,我实现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');"];
}
Run Code Online (Sandbox Code Playgroud)
这适用于所有情况,即使我的网页最终加载并报告ios is: undefined上述方法同时写入Can see JS from obj cXcode控制台.这似乎表明JSContext仍然有效,并且由于某种原因,它在JS中根本不再可见.
对这个非常冗长的问题道歉,关于这方面的文档很少,我认为我能提供的信息越多越好.
Mik*_*ike 17
页面加载可能导致WebView(以及包装WebView的UIWebView)获取新的JSContext.
如果这是我们讨论的MacOS,那么就像2013年WWDC中关于WebView的部分所示,在Apple的开发者网络上将"将JavaScript集成到本机应用程序"会话(https://developer.apple.com/videos/wwdc/2013 /?id = 615),您需要为框架加载实现委托,并在webView的选择器实现中初始化JSContext变量:didCreateJavaScriptContext:forFrame:
对于IOS,您需要在webViewDidFinishLoad中执行此操作:
-(void)webViewDidFinishLoad:(UIWebView *)view{
self.js = [view valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; // Undocumented access to UIWebView's JSContext
self.js[@"ios"] = self;
}
Run Code Online (Sandbox Code Playgroud)
之前的JSContext仍然可用于Objective-C,因为您已经保留了对它的强引用.
| 归档时间: |
|
| 查看次数: |
15281 次 |
| 最近记录: |