简体   繁体   English

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

[英]How do I call an Objective-C method from Javascript in UIWebView?

I'm developing a native iPhone app using Phonegap, so everything is done in HTML and JS. 我正在使用Phonegap开发本机iPhone应用程序,因此所有操作均以HTML和JS完成。 I am using the Flurry SDK for analytics and want to use the 我正在使用Flurry SDK进行分析,并希望使用

[FlurryAPI logEvent:@"EVENT_NAME"];

method to track events. 跟踪事件的方法。 Is there a way to do this in Javascript? 有没有办法用Javascript做到这一点? So when tracking a link I would imagine using something like 因此,当跟踪链接时,我会想象使用类似

<a onClick="flurryTrackEvent("Click_Rainbows")" href="#Rainbows">Rainbows</a>
<a onClick="flurryTrackEvent("Click_Unicorns")" href="#Unicorns">Unicorns</a>

"FlurryAPI.h" has the following: “ FlurryAPI.h”具有以下内容:

@interface FlurryAPI : NSObject {
}

+ (void)startSession:(NSString *)apiKey;
+ (void)logEvent:(NSString *)eventName;
+ (void)logEvent:(NSString *)eventName withParameters:(NSDictionary *)parameters;
+ (void)logError:(NSString *)errorID message:(NSString *)message exception:(NSException *)exception;

+ (void)setUserID:(NSString *)userID;
+ (void)setEventLoggingEnabled:(BOOL)value;
+ (void)setServerURL:(NSString *)url;
+ (void)setSessionReportsOnCloseEnabled:(BOOL)sendSessionReportsOnClose;

@end

I'm only interested in the logEvent method(s). 我只对logEvent方法感兴趣。 If it's not clear by now, I'm comfortable with JS but a recovering Obj-C noob. 如果现在还不清楚,我对JS很满意,但是对Obj-C的菜鸟有所了解。 I've read the Apple docs but the examples described there are all for newly declared methods and I imagine this could be simpler to implement because the Obj-C method(s) are already defined. 我已经阅读了Apple文档,但是其中描述的示例都是针对新声明的方法的,我认为这可能更易于实现,因为已经定义了Obj-C方法。

Thank you in advance for any input. 预先感谢您的任何投入。

One way to do this is to setup a delegate on the UIWebView which has the shouldStartLoadEvent. 一种实现方法是在UIWebView上设置一个具有shouldStartLoadEvent的委托。 Inside that event, you check what URL the UIWebView is trying to navigate to. 在该事件内,您检查UIWebView试图导航到的URL。 Now to communicate from JavaScript to Objective-C, you need to specify your own custom anchors which will trigger different actions. 现在要从JavaScript与Objective-C进行通信,您需要指定自己的自定义锚,这将触发不同的动作。 For example, to log something, you might decide to use the anchor "#FAPI_LogEvent_Click_Rainbows". 例如,要记录某些内容,您可能决定使用锚点“ #FAPI_LogEvent_Click_Rainbows”。

In JavaScript, you could have methods defined like such: 在JavaScript中,您可以定义如下方法:

function flurryTrackEvent(text) {
  window.location.href = 'FAPI_LogEvent' + text;
}
function flurrySetUserID(userID) {
  window.location.href = 'FAPI_SetUserID' + userID;
}

Next, in Objective-C, you would implement the shouldStartLoadEvent and "capture" these href navigations, and tell the browser not to load them. 接下来,在Objective-C中,您将实现shouldStartLoadEvent并“捕获”这些href导航,并告诉浏览器不要加载它们。 You will need to split the string up yourself and call the appropriate function. 您将需要自行拆分字符串并调用适当的函数。 Here's some code: 这是一些代码:

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

The fact that the events are already defined in Objective-C doesn't really help much since you need to implement your own routing behavior to call the appropriate Objective-C method. 事件已经在Objective-C中定义的事实并没有多大帮助,因为您需要实现自己的路由行为来调用适当的Objective-C方法。 The only way you could take advantage of the fact that the methods are already defined in Objective-C and avoid hard coding the routing logic, would be using @selectors or similar dynamic function calling which is available in Objective-C. 您可以利用以下事实的唯一方法是,已在Objective-C中定义了这些方法并避免对路由逻辑进行硬编码,那就是使用@selector或在Objective-C中可用的类似动态函数调用。 However, this is much more complicated to implement and probably presents a security risk. 但是,这实施起来要复杂得多,并可能带来安全风险。 I would recommend implementing the routing logic like is shown in the code above. 我建议实现上述代码中所示的路由逻辑。

Don't use their objective-c library, use their js library and you won't have to worry about objective-c. 不要使用他们的Objective-C库,而使用他们的js库,您就不必担心Objective-C。 :) :)

PhoneGap has functionality for adding native plugins, to add a Flurry log event plugin for iOS I would do something like this: PhoneGap具有添加本机插件,为iOS添加Flurry日志事件插件的功能,我将执行以下操作:

Add a PGFlurry PhoneGap plugin class: 添加一个PGFlurry PhoneGap插件类:

PGFlurry.h PGFlurry.h

#import <PhoneGap/PGPlugin.h>

@interface PGFlurry : PGPlugin
- (void)logEvent:(NSArray*)arguments withDict:(NSDictionary*)options;
@end

PGFlurry.m PGFlurry.m

#import "PGFlurry.h"
#import "FlurryAPI.h"

@implementation PGFlurry
// if you init Flurry somewhere else you can remove this method
- (PGPlugin*) initWithWebView:(UIWebView*)theWebView {
  self = [super init];
  if (self == nil) {
    return nil;
  }

  // init and start Flurry
  [FlurryAPI startSession:@"API key"];

  return self;
}

- (void)logEvent:(NSArray*)arguments withDict:(NSDictionary*)options {
  [FlurryAPI logEvent:[arguments objectAtIndex:0]];
}
@end

Add a JavaScript plugin helper to the www folder: 将JavaScript插件帮助程序添加到www文件夹:

Flurry.js Flurry.js

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

  window.plugins.flurry = {
    logEvent: function(name) {
      return PhoneGap.exec("PGFlurry.logEvent", name);
    }
  }
});

Add the plugin to PhoneGap.plist by adding a key/value pair with both the key and value being "PGFlurry" to the "plugins" dictionary. 通过将键和值对都添加为“ PGFlurry”的键/值对,将插件添加到PhoneGap.plist

Now you should be able to use it like this: 现在您应该可以像这样使用它:

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

You can find the Phonegap Flurry Plugin written by me at 您可以在以下位置找到由我编写的Phonegap Flurry插件

https://github.com/designerkamal/Phonegap-Flurry-Plugin https://github.com/designerkamal/Phonegap-Flurry-Plugin

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM