从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; } 

两个重要的说明:

  1. 上下文 :导航到myapp:whatever将(当然)在任何其他上下文失败。 请记住,如果您正在加载跨平台页面。

  2. 时机 :如果第二次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 } }