从 UIWebView 中的 javascript 向 ObjectiveC 发送通知

IT技术 javascript objective-c ios
2021-03-12 18:44:17

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

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

4个回答

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

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

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

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

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

// 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 对象

@dunforget,让我知道进展如何。我让这部分在一个测试项目中工作,所以如果你需要任何帮助,请告诉我。我现在正在测试 PhoneGap,到目前为止我印象深刻(易于设置!)
2021-05-11 18:44:17

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

例如,在捕获触摸事件时,我见过ontouchstartnot get sent via window.location,如果ontouchmove事件发生后很快(例如手指快速滑动)。因此你的 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
}

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

迅捷版

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