Returning values to JavaScript when calling an Objective-C function - Stack Overflow

I've been using WebViewJavascriptBridge to bridge Objective-C and JavaScript in an iOS application

I've been using WebViewJavascriptBridge to bridge Objective-C and JavaScript in an iOS application. It works great but it lacks support for returning values to the calling JavaScript code from the called native Objective-C function.

I'm pretty sure that Cordova (PhoneGap) does that in some way with callbacks but I've been having a hard time trying to understand how the underlying mechanics work.

Is there anyone who's had the same problem and that managed to find a solution?

I've been using WebViewJavascriptBridge to bridge Objective-C and JavaScript in an iOS application. It works great but it lacks support for returning values to the calling JavaScript code from the called native Objective-C function.

I'm pretty sure that Cordova (PhoneGap) does that in some way with callbacks but I've been having a hard time trying to understand how the underlying mechanics work.

Is there anyone who's had the same problem and that managed to find a solution?

Share Improve this question asked Sep 12, 2012 at 8:54 Valerio SantinelliValerio Santinelli 1,7022 gold badges29 silver badges47 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 4

Now, I've never used WebViewJavascriptBridge, but I have done this in objective-c using a simple delegate, so maybe this will help you:

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 ponentsSeparatedByCharactersInSet:[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;
}

Obviously this is much slower than trying to do the equivalent function in pure JS, because of all the loops it has to jump through. However, if there is something you need to use in your JS code that's in your ObjC code already, this may be for you.

If you mean, "return" in the sense that your JS caller will see the results as returned from the call, I don't know how to do it. I suspect it would take a level of thread manipulation not available in JS. Instead, you can recode your JS side logic to create a result handler function. In pseudo code:

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

Bees

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

Admittedly a bit awkward but get used to it - it is a very mon pattern. Internally, the JS bridge code creates a mapping of the request to the callback function. When the ObjC code has the result, it uses WebView's stringByEvaluatingJavaScriptFromString to call the JS bridge code that locates and invokes the callback.

@Richard - Be a bit careful with the solution you posted. Setting window.location to invoke shouldStartLoadWithRequest can result in both lost functionality in the webview and also lost messages to ObjectiveC. Current practice is to use an iframe and have some kind of message queue that can buffer up messages.

WebViewJavascriptBridgehave no maintain for a long time.

Maybe you should change to use this library.

SDBridgeOC

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

This can easy to get javascript console.log.

Also have Swift language Version.

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)
      }

Also have h5 demo for your partner.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744958007a4603312.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信