簡體   English   中英

調用 Objective-C 函數時將值返回給 JavaScript

[英]Returning values to JavaScript when calling an Objective-C function

我一直在使用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 並擁有某種可以緩沖消息的消息隊列。

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 演示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM