在调用Objective-C函数时将值返回到JavaScript



我一直在使用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;
    }
}

MyPage.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>

ViewController.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代码中了,那么这可能适合您。

如果你的意思是"return",即你的JS调用程序将看到调用返回的结果,我不知道该怎么做。我怀疑这需要JS中不可用的线程操作级别。相反,您可以重新编码JS端逻辑,以创建一个结果处理程序函数。在伪代码中:

res = CallObjC(args);
work with res...

成为

CallObjC(args, function(res) { work with res...});

诚然,这有点尴尬,但要习惯它——这是一种非常常见的模式。在内部,JS桥代码创建了一个请求到回调函数的映射。当ObjC代码得到结果时,它使用WebView的字符串ByEvaluatingJavaScriptFromString来调用定位并调用回调的JS桥代码。

@Richard-对你发布的解决方案要小心一点。将window.location设置为调用shouldStartLoadWithRequest可能会导致Web视图中的功能丢失,也会导致ObjectiveC的消息丢失。目前的做法是使用iframe并具有某种可以缓冲消息的消息队列。

WebViewJavascriptBridge长期不维护。

也许你应该改用这个图书馆。

SDBridgeOC

 self.bridge.consolePipeBlock = ^(id  _Nonnull water) {
        NSLog(@"Next line is javascript console.log------>>>>");
        NSLog(@"%@",water);
    };

这可以很容易地获得javascript console.log。

也有Swift语言版本。

SDBridgeSwift

bridge.consolePipeClosure = { water in
         guard let jsConsoleLog = water else {
             print("Javascript console.log give native is nil!")
              return
         }
         print("Next line is Javascript console.log----->>>>>>>")
         print(jsConsoleLog)
      }

也有h5演示给你的合作伙伴。

最新更新