如何在UIWebView中从Javascript调用Objective-C方法?

如何在UIWebView中从Javascript调用Objective-C方法?,javascript,ios,webkit,flurry,phonegap-plugins,Javascript,Ios,Webkit,Flurry,Phonegap Plugins,我正在使用Phonegap开发一个原生的iPhone应用程序,所以一切都是用HTML和JS完成的。我正在使用Flurry SDK进行分析,并希望使用 [FlurryAPI logEvent:@"EVENT_NAME"]; 方法来跟踪事件。有没有办法用Javascript实现这一点?因此,当跟踪链接时,我会想象使用 <a onClick="flurryTrackEvent("Click_Rainbows")" href="#Rainbows">Rainbows</a> &

我正在使用Phonegap开发一个原生的iPhone应用程序,所以一切都是用HTML和JS完成的。我正在使用Flurry SDK进行分析,并希望使用

[FlurryAPI logEvent:@"EVENT_NAME"];
方法来跟踪事件。有没有办法用Javascript实现这一点?因此,当跟踪链接时,我会想象使用

<a onClick="flurryTrackEvent("Click_Rainbows")" href="#Rainbows">Rainbows</a>
<a onClick="flurryTrackEvent("Click_Unicorns")" href="#Unicorns">Unicorns</a>
我只对logEvent方法感兴趣。如果现在还不清楚的话,我对JS很满意,但是一个正在恢复的Obj-C noob。我已经阅读了,但是这里描述的示例都是针对新声明的方法的,我想这可能更容易实现,因为Obj-C方法已经定义好了


提前感谢您的任何输入。

一种方法是在UIWebView上设置一个具有shouldStartLoad事件的委托。在该事件中,检查UIWebView试图导航到的URL。现在要从JavaScript到Objective-C进行通信,您需要指定自己的自定义锚定,它将触发不同的操作。例如,要记录某些内容,您可能会决定使用锚定“#FAPI_LogEvent_Click_Rainbows”

在JavaScript中,可以定义如下方法:

function flurryTrackEvent(text) {
  window.location.href = 'FAPI_LogEvent' + text;
}
function flurrySetUserID(userID) {
  window.location.href = 'FAPI_SetUserID' + userID;
}
接下来,在Objective-C中,您将实现shouldStartLoadEvent并“捕获”这些href导航,并告诉浏览器不要加载它们。您需要自己拆分字符串并调用相应的函数。下面是一些代码:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType () {
  NSString *theAnchor = [[request URL] fragment];
  if ([theAnchor hasPrefix:@"FAPI_LogEvent"]) {
    NSString *textToLog = [theAnchor substringFromIndex:[@"FAPI_LogEvent" length]];
    [FlurryAPI logEvent:textToLog];
    return NO; // prevent the UIWebView from navigating to this anchor
  } else if ([theAnchor hasPrefix:@"FAPI_SetUserID"]) {
    NSString *userID = [theAnchor substringFromIndex:[@"FAPI_SetUserID" length]];
    [FlurryAPI setUserID:userID];
    return NO; // prevent the UIWebView from navigating to this anchor
  }
}

事实上,事件已经在Objective-C中定义,这并没有多大帮助,因为您需要实现自己的路由行为来调用适当的Objective-C方法。利用Objective-C中已经定义了方法这一事实并避免硬编码路由逻辑的唯一方法是使用@Selector或Objective-C中可用的类似动态函数调用。但是,这一方法的实现要复杂得多,可能会带来安全风险。我建议实现上述代码中所示的路由逻辑。

PhoneGap具有添加本机插件的功能,要为iOS添加Flurry日志事件插件,我将执行以下操作:

<!DOCTYPE html>
<html>
  <head>
    <script src="phonegap.js" type="text/javascript"></script>
    <script src="flurry.js" type="text/javascript"></script>
    <script type="text/javascript">
      document.addEventListener("deviceready", function() {
        window.plugins.flurry.logEvent("Testing");
      }, false);
    </script>
  </head>
  <body>
  </body>
</html>
添加一个
PGFlurry
PhoneGap插件类:

PGFlurry.h

#import <PhoneGap/PGPlugin.h>

@interface PGFlurry : PGPlugin
- (void)logEvent:(NSArray*)arguments withDict:(NSDictionary*)options;
@end
将JavaScript插件帮助程序添加到
www
文件夹:

Flurry.js

PhoneGap.addConstructor(function() {
  if(!window.plugins) {
    window.plugins = {};
  }

  window.plugins.flurry = {
    logEvent: function(name) {
      return PhoneGap.exec("PGFlurry.logEvent", name);
    }
  }
});
通过在“plugins”字典中添加一个键/值对,键和值都为“PGFlurry”,将插件添加到
PhoneGap.plist

现在,您应该可以这样使用它:

<!DOCTYPE html>
<html>
  <head>
    <script src="phonegap.js" type="text/javascript"></script>
    <script src="flurry.js" type="text/javascript"></script>
    <script type="text/javascript">
      document.addEventListener("deviceready", function() {
        window.plugins.flurry.logEvent("Testing");
      }, false);
    </script>
  </head>
  <body>
  </body>
</html>

document.addEventListener(“deviceready”,函数(){
window.plugins.flurry.logEvent(“测试”);
},假);

您可以在以下网址找到我编写的Phonegap Flurry插件


不要使用他们的objective-c库,使用他们的js库,您就不必担心objective-c.:)

这是有道理的,老鹰,谢谢你的领先。您是否有任何指向实际Obj-C代码的指针来帮助我入门?我更新了示例,使用未经测试的代码而不是伪代码。至于触发此事件,您需要了解如何使用委托模式。基本上,您需要设置视图控制器以实现UIWebViewDelegate协议,然后在Interface Builder中,您需要将其作为UIWebView的委托进行链接。我认为这篇博文将回答您的所有问题:我认为使用
NSSelectorFromString
实际上更易于实现,但是关于安全性,您是绝对正确的-可能最好保留一个可接受的选择器名称的
NSSet
,并且仅当指定的字符串在其中时才继续。
<!DOCTYPE html>
<html>
  <head>
    <script src="phonegap.js" type="text/javascript"></script>
    <script src="flurry.js" type="text/javascript"></script>
    <script type="text/javascript">
      document.addEventListener("deviceready", function() {
        window.plugins.flurry.logEvent("Testing");
      }, false);
    </script>
  </head>
  <body>
  </body>
</html>