我一直在使用WebViewJavascriptBridge在 iOS 应用程序中连接 Objective-C 和 JavaScript。它工作得很好,但它不支持从被调用的本机 Objective-C 函数返回值给调用 JavaScript 代码。
我很确定 Cordova (PhoneGap) 在某种程度上通过回调做到了这一点,但我一直很难理解底层机制是如何工作的。
有没有人遇到同样的问题并设法找到解决方案?
我一直在使用WebViewJavascriptBridge在 iOS 应用程序中连接 Objective-C 和 JavaScript。它工作得很好,但它不支持从被调用的本机 Objective-C 函数返回值给调用 JavaScript 代码。
我很确定 Cordova (PhoneGap) 在某种程度上通过回调做到了这一点,但我一直很难理解底层机制是如何工作的。
有没有人遇到同样的问题并设法找到解决方案?
现在,我从未使用过 WebViewJavascriptBridge,但我已经在 Objective-C 中使用简单的委托完成了这项工作,所以也许这会对您有所帮助:
MyScript.js
// requestFromObjc
// functionName (required):
// the name of the function to pass along to objc
// returnedResult (not used by caller):
// the result given by objc to be passed along
// callback (not used by caller):
// sent by objc, name of the function to execute
function requestFromObjc(functionName, objcResult, callback)
{
if (!objcResult)
{
window.location = "myapp://objcRequest?function=" + functionName + "&callback=" + arguments.callee.name + "&callbackFunc=" + arguments.callee.caller.name;
}
else
{
window[callback](objcResult);
}
}
function buttonClick(objcResult)
{
if (!objcResult)
{
// ask for the color from objc
requestFromObjc("buttonColor&someParam=1");
}
else
{
// do something with result (in this case, set the background color of my div)
var div = document.getElementById("someDiv");
div.style.background = objcResult;
}
}
我的页面.html
<html>
<head>
<script type="text/javascript" src="MyScript.js"></script>
</head>
<body>
<div id="someDiv">
This is my div! Do not make fun of it, though.
</div>
<button onClick="buttonClick(undefined)">
Click Me!
</button>
</body>
</html>
视图控制器.m
-(NSString *) javaScriptResultForRequest:(NSDictionary *) params
{
if ([params[@"function"] isEqualToString:@"buttonColor"])
{
NSArray *colors = @[ @"red", @"yellow", @"blue", @"green", @"purple" ];
return colors[arc4random_uniform(colors.count)];
}
else
{
return @"undefined";
}
}
-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if ([[[request URL] scheme] isEqualToString:@"myapp"])
{
// parse the URL here
NSURL *URL = [request URL];
if ([URL.host isEqualToString:@"objcRequest"])
{
NSMutableDictionary *queryParams = [NSMutableDictionary dictionary];
NSArray *split = [URL.query componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"&="]];
for (int i = 0; i < split.count; i += 2)
{
queryParams[split[i]] = split[i + 1];
}
NSString *result = [self javaScriptResultForRequest:queryParams];
NSString *jsRequest = [NSString stringWithFormat:@"%@(\"%@\", \"%@\", \"%@\")", queryParams[@"callback"], queryParams[@"function"], result, queryParams[@"callbackFunc"]];
// now we send this to the target
[self.webView stringByEvaluatingJavaScriptFromString:jsRequest];
return NO;
}
}
return YES;
}
显然这比尝试在纯 JS 中执行等效功能要慢得多,因为它必须跳过所有循环。但是,如果您需要在您的 JS 代码中使用已经在您的 ObjC 代码中的东西,那么这可能适合您。
如果您的意思是“返回”,因为您的 JS 调用者将看到调用返回的结果,我不知道该怎么做。我怀疑这需要 JS 中没有的线程操作级别。相反,您可以重新编码 JS 端逻辑以创建结果处理函数。在伪代码中:
res = CallObjC(args);
work with res...
变成
CallObjC(args, function(res) { work with res...});
诚然有点尴尬,但习惯了 - 这是一种非常常见的模式。在内部,JS 桥接代码创建了请求到回调函数的映射。当 ObjC 代码有结果时,它使用 WebView 的 stringByEvaluatingJavaScriptFromString 调用定位并调用回调的 JS 桥代码。
@Richard - 请注意您发布的解决方案。将 window.location 设置为调用 shouldStartLoadWithRequest 会导致 webview 中的功能丢失以及 ObjectiveC 的消息丢失。当前的做法是使用 iframe 并拥有某种可以缓冲消息的消息队列。