【问题标题】:How to call Objective-C from Javascript?如何从 Javascript 调用 Objective-C?
【发布时间】:2010-12-12 08:37:00
【问题描述】:

我有一个 WebView,我想从 JavaScript 调用 Objective-C 中的一个视图。有人知道我该怎么做吗?


我的 ViewController 中有这段代码:

- (BOOL)webView:(UIWebView *)webView2 
 shouldStartLoadWithRequest:(NSURLRequest *)request 
 navigationType:(UIWebViewNavigationType)navigationType {

 NSString *requestString = [[request URL] absoluteString];
 NSArray *components = [requestString componentsSeparatedByString:@":"];

 if ([components count] > 1 && 
  [(NSString *)[components objectAtIndex:0] isEqualToString:@"myapp"]) {
  if([(NSString *)[components objectAtIndex:1] isEqualToString:@"myfunction"]) 
  {

   NSLog([components objectAtIndex:2]); [[Airship shared] displayStoreFront]; //<- This is the code to open the Store
   NSLog([components objectAtIndex:3]); // param2
   // Call your method in Objective-C method using the above...
  }
  return NO;
 }

 return YES; // Return YES to make sure regular navigation works as expected.
}

在 Javascript 中:

function store(event)
{
    document.location = "myapp:" + "myfunction:" + param1 + ":" + param2;
}

但什么也没发生。

【问题讨论】:

标签: iphone cocoa-touch uiwebview


【解决方案1】:

虽然这是一个非常古老的问题,但它不断被谷歌返回,现在有一个很好的答案:WebScripting 非正式协议。它允许您向 Javascript 公开一个客观的 C 对象。

http://developer.apple.com/library/safari/documentation/appleapplications/Conceptual/SafariJSProgTopics/Tasks/ObjCFromJavaScript.html#//apple_ref/doc/uid/30001215-BBCBFJCD

【讨论】:

    【解决方案2】:

    Obliviux,

    您的代码似乎很完美。

    问题的原因是您一定错过了映射委托。

    要么

    1. 将 webView 的代理连接到 .xib 文件中的文件所有者

    1. 使用webView.delegate = self;

    在你的viewDidLoad

    谢谢

    【讨论】:

      【解决方案3】:

      不推荐JS调用objective c的window.location方法。问题的一个示例:如果您立即连续拨打两个电话,则其中一个会被忽略(因为您不能太快更改位置) - 自己尝试一下..

      我推荐以下替代方法:

      function execute(url) 
      {
        var iframe = document.createElement("IFRAME");
        iframe.setAttribute("src", url);
        document.documentElement.appendChild(iframe);
        iframe.parentNode.removeChild(iframe);
        iframe = null;
      }
      

      您反复调用execute 函数,由于每次调用都在其自己的 iframe 中执行,因此在快速调用时不应忽略它们。

      感谢this guy

      【讨论】:

      • 为什么要把null分配给最后一行的iframe? (它不强制垃圾收集或提供任何其他利润)
      【解决方案4】:

      我在使用这种方法时遇到了问题:我想向 iPhone 设备发送几条消息,但它们似乎“重叠”了,因为它们无法按顺序处理所有消息。

      示例:执行此代码时:

      window.location = "app://action/foo";
      window.location = "app://action/bar";
      

      从未执行过foo 操作。

      我必须做的是:

      waitingForMessage = false;
      
      function MsgProcessed(){
          waitingForMessage = false;
      }
      
      function SyncLaunchURL(url){
          if (waitingForMessage){
              setTimeout(function(){SyncLaunchURL(url)},100);
          }else{
              window.location = url
              waitingForMessage = true;   
          }
      }
      
      SyncLaunchURL("app://action/foo");
      SyncLaunchURL("app://action/bar");
      

      使用这种方法,iphone 必须在处理完呼叫后调用 MsgProcessed()。这种方式对我有用,也许可以帮助有同样问题的人!

      【讨论】:

      • 如果只是用setTimeout异步设置窗口位置就不行?
      • 你仍然有一个问题,如果 window.location 没有被处理,它会丢弃那个“位置”。
      • 看我的回答,它似乎解决了这个问题,没有轮询或估计的延迟.. setTimeout 解决方案不是很优雅:)
      • 请不要这样做。听@talkol。
      【解决方案5】:

      检查这个-understanding XMLHttpRequest responses using this (or other javascript) functions?,它使用objective C调用ajax js函数,并在它完成后得到响应,你知道诀窍是当你在javascript中更改位置时会触发webview,所以你可以检查位置以了解您的 javascript 调用或实际请求。

      【讨论】:

        【解决方案6】:

        就像人们在这里说的,你必须使用来自 UIWebviewDelegate 的 webView:shouldStartLoadWithRequest:navigationType: 方法。

        这个 api http://code.google.com/p/jsbridge-to-cocoa/ 为你做。它非常轻巧。您可以将图像、字符串和数组从 javascript 传递到 Objective-C。

        【讨论】:

        • 您可能需要编辑您的答案,因为无法将图像从 javascript 发送到目标 c。您展示的示例只是通过 window.location 方式将图像的 id 从 javascript 传递到目标 c。此外,图像位于本地主包中。
        【解决方案7】:

        假设您正在开发一个应用程序,您可以查看PhoneGap 是如何实现的(甚至是使用它)。它是一个支持 JS 和 OBJ-C 之间来回通信的库。还有其他库和解决方案。

        如果您谈论的是 Web 应用程序(用户从 Mobile Safari 获得的东西),那么您无法从那里获得 Objective-C。

        【讨论】:

          【解决方案8】:

          UIWebView 的标准解决方法是设置UIWebViewDelegate,并实现webView:shouldStartLoadWithRequest:navigationType: 方法。在您的 JavaScript 代码中,导航到一些虚假 URL,该 URL 对您要传递给应用的信息进行编码,例如:

          window.location = "fake://myApp/something_happened:param1:param2:param3";
          

          在您的委托方法中,查找这些虚假 URL,提取您需要的信息,采取任何适当的操作,然后返回 NO 以取消导航。最好使用some flavor of performSelector 推迟任何冗长的处理。

          【讨论】:

          • 这个方案的问题是如果“fake//...”加载失败,webview:shouldStartLoadWithRequest:navigationType: 将不会被调用。有什么办法解决吗?
          • 在调用webview:shouldStartLoadWithRequest:navigationType: 之前会导致它失败的原因是什么? (这个回调的重点是它发生在之前系统开始任何网络加载等)
          • 我推荐serializing the data you're passing in the URL as JSON,它让事情变得更加灵活。
          • 你可以通过cordova.exec(function(success){ alert('success'); console.log(success); }, function(fail){ console.日志(失败); }, '','',[]);并将这一行添加到 config.xml
          • 没有任何关于这个问题的假设是应用程序正在使用 Cordova,但如果你是,并且他们为此提供了一个帮助函数,那就很方便了。
          猜你喜欢
          • 2012-04-29
          • 1970-01-01
          • 2014-03-22
          • 1970-01-01
          • 1970-01-01
          • 2011-02-13
          • 2017-10-15
          • 2013-01-11
          • 1970-01-01
          相关资源
          最近更新 更多