【问题标题】:How do I call an Objective-C method from Javascript in UIWebView?如何在 UIWebView 中从 Javascript 调用 Objective-C 方法?
【发布时间】:2011-02-13 14:09:15
【问题描述】:

我正在使用 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>

“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

我只对 logEvent 方法感兴趣。如果现在还不清楚,我对 JS 很满意,但我是一个正在恢复的 Obj-C 菜鸟。我已经阅读了Apple docs,但其中描述的示例都是针对新声明的方法,我想这可能更容易实现,因为已经定义了 Obj-C 方法。

提前感谢您的任何意见。

【问题讨论】:

    标签: javascript ios webkit flurry phonegap-plugins


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      你可以在

      找到我写的Phonegap Flurry插件

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

      【讨论】:

        【解决方案3】:

        PhoneGap 具有添加原生插件的功能,要为 iOS 添加 Flurry 日志事件插件,我会这样做:

        添加一个PGFlurryPhoneGap 插件类:

        PGFlurry.h

        #import <PhoneGap/PGPlugin.h>
        
        @interface PGFlurry : PGPlugin
        - (void)logEvent:(NSArray*)arguments withDict:(NSDictionary*)options;
        @end
        

        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
        

        将 JavaScript 插件助手添加到 www 文件夹:

        Flurry.js

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

        将插件添加到PhoneGap.plist,方法是将键和值都为“PGFlurry”的键/值对添加到“插件”字典中。

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

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

        【讨论】:

          【解决方案4】:

          一种方法是在 UIWebView 上设置一个委托,该委托具有 shouldStartLoadEvent。在该事件中,您检查 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 中定义并避免硬编码路由逻辑这一事实的唯一方法是使用 @selectors 或 Objective-C 中可用的类似动态函数调用。但是,这实现起来要复杂得多,并且可能会带来安全风险。我建议像上面的代码那样实现路由逻辑。

          【讨论】:

          • 这很有意义,老鹰,感谢您的领先。您是否有任何指向实际 Obj-C 代码的指针来帮助我入门?
          • 我更新了示例以使用 untested 代码而不是伪代码。至于触发此事件,您需要阅读有关如何使用委托模式的信息。本质上,您需要设置视图控制器来实现 UIWebViewDelegate 协议,然后在 Interface Builder 中,您需要将其链接为 UIWebView 的委托。
          • 我认为这篇博文会回答你所有的问题:codingventures.com/2008/12/using-uiwebview-to-render-svg-files
          • 我认为使用 NSSelectorFromString 实际上会更容易实现,但你对安全性的看法是绝对正确的——可能最好保留一个可接受的选择器名称的 NSSet,并且只有在指定的字符串是在那里。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-04-29
          • 2014-03-22
          • 1970-01-01
          • 1970-01-01
          • 2011-02-21
          • 2023-03-29
          相关资源
          最近更新 更多