iOS JavaScript bridge

iOS JavaScript bridge

本文关键字:bridge JavaScript iOS      更新时间:2023-09-26

我正在开发一个应用程序,在该应用程序中,我将同时使用UIWebView中的HTML5和本机iOS框架。我知道我可以实现JavaScript和Objective-C之间的通信。有没有任何库可以简化这种通信的实现?我知道有几个库可以用HTML5和javascript创建原生iOS应用程序(例如AppMobi、PhoneGap),但我不确定是否有库可以帮助创建大量使用javascript的原生iOS应用。我需要:

  1. 从Objective-C执行JS方法
  2. 从JS执行Objective-C方法
  3. 监听Objective-C中的本地JS事件(例如DOM就绪事件)

有一些库,但我在大型项目中没有使用过它们,所以你可能想试用一下:

  • WebViewJavascriptBridge:https://github.com/marcuswestin/WebViewJavascriptBridge
  • GAJavaScript:https://github.com/newyankeecodeshop/GAJavaScript

--

然而,我认为这很简单,你可以自己尝试一下。当我需要这样做的时候,我个人就这样做了。您也可以创建一个简单的库来满足您的需求。

1.从Objective-C执行JS方法

这实际上只是一行代码。

NSString *returnvalue = [webView stringByEvaluatingJavaScriptFromString:@"your javascript code string here"];

有关UIWebView官方文档的更多详细信息。

2.从JS执行Objective-C方法

不幸的是,这稍微复杂一点,因为MacOSX上没有相同的windowScriptObject属性(和类)允许两者之间完全通信。

然而,您可以很容易地从javascript定制的URL进行调用,如:

window.location = yourscheme://callfunction/parameter1/parameter2?parameter3=value

并从Objective-C中截取:

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
   NSURL *URL = [request URL]; 
   if ([[URL scheme] isEqualToString:@"yourscheme"]) {
       // parse the rest of the URL object and execute functions
   } 
}

这并不像它应该的那样干净(或者通过使用windowScriptObject),但它是有效的。

3.监听Objective-C中的原生JS事件(例如DOM就绪事件)

从上面的解释中,您可以看到,如果要做到这一点,您必须创建一些JavaScript代码,将其附加到要监视的事件,并调用正确的window.location调用,然后进行拦截。

再说一次,虽然它不应该是干净的,但它是有效的。

不推荐在接受的答案中从JS调用目标c的建议方法。问题的一个例子是:如果您立即连续拨打两个电话,其中一个会被忽略(您不能太快更改位置)。

我推荐以下替代方法:

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

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

归功于这个家伙。

更新:这在iOS 8中发生了变化。我的回答适用于以前的版本。

另一种可能会让你被应用商店拒绝的选择是使用WebScriptObject。

这些API在OSX上是公开的,但在iOS上不是。

您需要定义内部类的接口。

@interface WebScriptObject: NSObject
@end
@interface WebView
- (WebScriptObject *)windowScriptObject;
@end
@interface UIWebDocumentView: UIView
- (WebView *)webView;
@end

您需要定义将用作WebScriptObject 的对象

@interface WebScriptBridge: NSObject
- (void)someEvent: (uint64_t)foo :(NSString *)bar;
- (void)testfoo;
+ (BOOL)isKeyExcludedFromWebScript:(const char *)name;
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector;
+ (WebScriptBridge*)getWebScriptBridge;
@end
static WebScriptBridge *gWebScriptBridge = nil;
@implementation WebScriptBridge
- (void)someEvent: (uint64_t)foo :(NSString *)bar
{
    NSLog(bar);
}
-(void)testfoo {
    NSLog(@"testfoo!");
}
+ (BOOL)isKeyExcludedFromWebScript:(const char *)name;
{
    return NO;
}
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector;
{
    return NO;
}
+ (NSString *)webScriptNameForSelector:(SEL)sel
{
    // Naming rules can be found at: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/WebKit/Protocols/WebScripting_Protocol/Reference/Reference.html
    if (sel == @selector(testfoo)) return @"testfoo";
    if (sel == @selector(someEvent::)) return @"someEvent";
    return nil;
}
+ (WebScriptBridge*)getWebScriptBridge {
    if (gWebScriptBridge == nil)
        gWebScriptBridge = [WebScriptBridge new];
    return gWebScriptBridge;
}
@end

现在将该实例设置为UIWebView

if ([uiWebView.subviews count] > 0) {
    UIView *scrollView = uiWebView.subviews[0];
    for (UIView *childView in scrollView.subviews) {
        if ([childView isKindOfClass:[UIWebDocumentView class]]) {
            UIWebDocumentView *documentView = (UIWebDocumentView *)childView;
            WebScriptObject *wso = documentView.webView.windowScriptObject;
            [wso setValue:[WebScriptBridge getWebScriptBridge] forKey:@"yourBridge"];
        }
    }
}

现在,在您的javascript中,您可以调用:

yourBridge.someEvent(100, "hello");
yourBridge.testfoo();

在iOS8中,您可以查看WKWebView而不是UIWebView。它具有以下类别:WKScriptMessageHandler:提供一种从网页中运行的JavaScript接收消息的方法。

这在iOS7中是可能的,请检查http://blog.bignerdranch.com/3784-javascriptcore-and-ios-7/

您的最佳选择是Appcelerators Titanium产品。他们已经使用webkit使用的V8引擎JavascriptCore引擎构建了一个Obj-C javascript桥。它也是开源的,所以你可以下载它,并根据自己的喜好修改Obj-C。

看看KirinJS项目:KirinJS允许将Javascript用于应用程序逻辑和原生UI,足以满足其运行的平台。

我创建了一个类似WebViewJavascriptBridge的库,但它更像JQuery,更容易设置,也更容易使用。不依赖jQuery(尽管值得称赞的是,如果我在写这篇文章之前就知道WebViewJavascriptBridge的存在,我可能只是在深入研究之前稍微犹豫了一下)。让我知道你的想法!jodgejs

如果您在iOS 8上使用WKWebView,请查看XWebView,它可以自动向javascript公开本机接口。