从UIWebView中的JavaScript发送通知到ObjectiveC
我需要知道在UIWebView
的HTML中使用JavaScript来通知Objective-C发生了什么事情?
更准确地说,我在HTML中播放一些JavaScriptanimation,并且需要提醒animation已经结束的Objective-C代码。
似乎没有这样做的官方方法。 但是, 标准的 解决方法涉及读取和parsing传入的URL请求,基本上是滚动您自己的序列化的消息传递协议。 消息处理应该在视图控制器的webView:shouldStartLoadWithRequest:navigationType
方法中完成。
注意:有几个免费的库( PhoneGap , QuickConnect , JS到Cocoa Bridge )包装了这个function(加上做了很多)。 为了重新发明轮子(或者知道为什么轮子可以这么说),请继续阅读。
从JavaScript中,您将通过尝试导航到新的URL来调用callback:
// In JavaScript window.location = 'myapp:myaction:param1:param2'; // etc...
在Objective-C中,在.h
文件中实现UIWebViewDelegate
协议:
// In your header file @interface MyAppViewController : UIViewController <UIWebViewDelegate> { ... } @end
接下来,在.m
文件中实现该方法:
// In your implementation file -(BOOL)webView:(UIWebView *)webView2 shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { // Break apart request URL NSString *requestString = [[request URL] absoluteString]; NSArray *components = [requestString componentsSeparatedByString:@":"]; // Check for your protocol if ([components count] > 1 && [(NSString *)[components objectAtIndex:0] isEqualToString:@"myapp"]) { // Look for specific actions if ([(NSString *)[components objectAtIndex:1] isEqualToString:@"myaction"]) { // Your parameters can be found at // [components objectAtIndex:n] // where 'n' is the ordinal position of the colon-delimited parameter } // Return 'NO' to prevent navigation return NO; } // Return 'YES', navigate to requested URL as normal return YES; }
两个重要的说明:
-
上下文 :导航到
myapp:whatever
将(当然)在任何其他上下文失败。 请记住,如果您正在加载跨平台页面。 -
时机 :如果第二次
window.location =
调用在第一次返回之前发生,它将会“丢失”。 所以,要么将你的调用集中在一起,要么手动延迟执行,要么实现一个将上面的JS查询结合到Objective-C对象中的队列。
其实对于iOS的时间(可能不适用于OSX?),如果在执行前一个window.location
调用之前执行第二个window.location
调用,则第一个window.location
调用将会丢失。 我认为window.location
调用在调用JavaScript之后会与JavaScript非同步地执行,如果在执行之前调用另一个调用,则取消第一个调用。
例如,当捕获触摸事件时,如果之后发生ontouchmove
事件(例如快速滑动),则看到ontouchstart
不会通过window.location
发送。 因此你的Objective-C没有得到ontouchstart
事件。 原来iPad上的这个问题比iPad2更有问题,我假设是因为处理速度。
zourtney的答案是正确的,但忘了提及一件事情..需要注册代表webview
- (void)viewDidLoad { [super viewDidLoad]; --- instantiate _webview next .. then _webview.delegate = self; //important .. needed to register webview to delegate }
希望这可以帮助 …..
Swift版本
class ViewController: UIViewController,UIWebViewDelegate{ @IBOutlet weak var webviewInstance: UIWebView! override func viewDidLoad() { webviewInstance.delegate = self super.viewDidLoad() } func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool { let requestString: String = (request.URL?.absoluteString)! var components: [AnyObject] = requestString.componentsSeparatedByString(":") // Check for your protocol if components.count > 1 && (String(components[0]) == "myapp") { // Look for specific actions if (String(components[1]) == "myaction") { // Your parameters can be found at // [components objectAtIndex:n] } return false } return true } }