从 UIWebView 中的 javascript 向 ObjectiveC 发送通知

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5671742/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 17:58:58  来源:igfitidea点击:

send a notification from javascript in UIWebView to ObjectiveC

javascriptobjective-cios

提问by mkto

I need to know what should be done to use JavaScript in a HTML sitting in UIWebViewto notify Objective-C that something has happened?

我需要知道应该怎么做才能在 HTML 中使用 JavaScriptUIWebView来通知 Objective-C 发生了一些事情?

To be more exact, I'm playing some JavaScript animation in HTML and I need to alert the Objective-C code that the animation has ended.

更准确地说,我正在用 HTML 播放一些 JavaScript 动画,我需要提醒 Objective-C 代码动画已经结束。

回答by Courtney Christensen

There seems to be no official method of doing this. However, thestandardworkaroundinvolves reading and parsing incoming URL requests, basically rolling your own serialized messaging protocol. The message handling should be done in the webView:shouldStartLoadWithRequest:navigationTypemethod of your view controller.

似乎没有这样做的官方方法。然而,标准的解决方法包括读取和解析传入的URL请求,基本上滚动你自己的序列化的消息传递协议。消息处理应该在webView:shouldStartLoadWithRequest:navigationType视图控制器的方法中完成。

Note: there are several free libraries (PhoneGap, QuickConnect, JS-to-Cocoa Bridge) which wrap this functionality (plus do a whole lot more). To reinvent the wheel (or know why it's round, so to speak), read on.

注意:有几个免费的库(PhoneGapQuickConnectJS-to-Cocoa Bridge)包装了这个功能(还有更多)。要重新发明轮子(或者知道它为什么是圆的,可以这么说),请继续阅读。

From JavaScript, you will invoke the callback by attempting to navigate to a new URL:

在 JavaScript 中,您将通过尝试导航到新 URL 来调用回调:

// In JavaScript
window.location = 'myapp:myaction:param1:param2'; // etc...

In Objective-C, implement the UIWebViewDelegateprotocol in your .hfile:

在 Objective-C 中,UIWebViewDelegate在你的.h文件中实现协议:

// In your header file
@interface MyAppViewController : UIViewController <UIWebViewDelegate> {
  ...
}
@end

Next, implement the method in your .mfile:

接下来,在您的.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;
}

Two important notes:

两个重要的注意事项:

  1. Context: navigating to myapp:whateverwill (of course) fail under any other context. Keep this in mind if you're loading cross-platform pages.

  2. Timing: if a second window.location =call is made before the first returns, it will get 'lost.' So, either lump your calls together, manually delay execution, or implement a queue which combines the above with JS queries into Objective-C objects.

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

  2. 时间:如果window.location =在第一次返回之前进行第二次调用,它将“丢失”。因此,要么将您的调用集中在一起,手动延迟执行,要么实现一个队列,将上述内容与JS 查询组合成 Objective-C 对象

回答by Thorpedo

Actually for timing in iOS (maybe not for OSX?), if a second window.locationcall is made before the previous window.locationcall executes, then the first window.locationcall gets lost. I think the window.locationcall executes asynchronisely with the JavaScript after it is called, and if another call is made it before it executes, it cancels the first.

实际上对于 iOS 中的计时(可能不适用于 OSX?),如果window.location在前一个window.location调用执行之前进行了第二个调用,那么第一个window.location调用就会丢失。我认为window.location调用在调用后与 JavaScript 异步执行,如果在执行之前进行了另一个调用,它会取消第一个调用。

For example, when capturing touch events, I have seen ontouchstartnot get sent via window.location, if an ontouchmoveevent occurs to quickly afterwards (such as in a fast finger swipe). Thus your Objective-C doesn't get the ontouchstartevent. This is more of a problem on the original iPad than the iPad2, I assume because of processing speed.

例如,在捕获触摸事件时,我见过ontouchstartnot get sent via window.location,如果ontouchmove事件发生后很快(例如手指快速滑动)。因此你的 Objective-C 没有得到ontouchstart事件。这在原始 iPad 上比 iPad2 上的问题更大,我认为是因为处理速度。

回答by Aneer Dev

zourtney's answer is correct , but forgot to mention one thing .. needed to register delegate to webview by

zourtney 的回答是正确的,但忘了提一件事.. 需要通过以下方式将委托注册到 webview

- (void)viewDidLoad {
    [super viewDidLoad];  --- instantiate _webview next .. then 

    _webview.delegate = self;  //important .. needed to register webview to delegate
}

hope this helps .....

希望这可以帮助 .....

回答by johisco

Swift Version

迅捷版

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