我正在开发一个应用程序,我将在UIWebView和本机iOS框架中同时使用HTML5。我知道我可以实现JavaScript和Objective-C之间的通信。是否有任何库可以简化实现此通信?我知道有几个库可以用HTML5和javascript(例如AppMobi,PhoneGap)创建本机iOS应用程序,但我不确定是否有一个库来帮助创建使用大量JavaScript的本机iOS应用程序。我需要:
答案 0 :(得分:149)
有一些库,但我没有在大项目中使用过这些库,所以你可能想尝试一下:
-
但是,我觉得这很简单,你可以自己尝试一下。当我需要这样做时,我个人就是这样做的。您也可以创建一个适合您需求的简单库。
这只是一行代码。
NSString *returnvalue = [webView stringByEvaluatingJavaScriptFromString:@"your javascript code string here"];
有关官方UIWebView Documentation的更多详情。
遗憾的是,这有点复杂,因为Mac OSX上不存在相同的windowScriptObject属性(和类),允许两者之间完全通信。
但是,您可以通过javascript自定义网址轻松调用,例如:
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),但它可以工作。
从上面的解释中,您可以看到,如果您想这样做,您必须创建一些JavaScript代码,将其附加到您要监控的事件并调用正确的window.location
调用然后被截获。
同样,不应该干净,但它确实有效。
答案 1 :(得分:57)
建议不要在接受的答案中使用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中执行,所以在快速调用时不应忽略它们。
致this guy的信用。
答案 2 :(得分:12)
更新: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();
答案 3 :(得分:5)
In iOS8 you can look at WKWebView instead of UIWebView。这有以下几类: WKScriptMessageHandler:提供从网页中运行的JavaScript接收消息的方法。
答案 4 :(得分:3)
这可以通过iOS7,结帐http://blog.bignerdranch.com/3784-javascriptcore-and-ios-7/
来实现答案 5 :(得分:0)
您最好的选择是Appcelerators Titanium产品。他们已经使用webkit使用的 V8引擎 JavascriptCore引擎构建了一个Obj-C javascript桥。它也是开源的,所以你可以下载它并随意修改Obj-C。
答案 6 :(得分:0)
查看KirinJS项目:Kirin JS,它允许使用Javascript作为应用程序逻辑和本机UI,足以运行它所运行的平台。
答案 7 :(得分:0)
我创建了一个类似WebViewJavascriptBridge的库,但它更像JQuery,更容易设置并且更易于使用。不依赖于jQuery(尽管如此,如果我在写这篇文章之前知道WebViewJavascriptBridge存在,我可能会在潜入之前稍微停下来)。让我知道你的想法! jockeyjs
答案 8 :(得分:0)
如果您在iOS 8上使用WKWebView,请查看XWebView,它可以自动将原生界面公开给javascript。