iOS Native 與 JS 交互

對(duì)于 iOS Native 與 JS 交互我們先從調(diào)用方向上分為兩種情況來看:

JS 調(diào)用 Native
Native 調(diào)用 JS

  1. JS 調(diào)用 Native

其實(shí) JS 調(diào)用 iOS Native 也分為兩種實(shí)現(xiàn)方式:

a. 假 Request 方法
b. JavaScriptCore 方法

a. 假 Request 方法

原理:其實(shí)這種方式就是利用了 webview 的代理方法,在 webview 開始請(qǐng)求的時(shí)候截獲請(qǐng)求,判斷請(qǐng)求是否為約定好的假請(qǐng)求。如果是假請(qǐng)求則表示是 JS 想要按照約定調(diào)用我們的 Native 方法,按照約定去執(zhí)行我們的 Native 代碼就好。

① UIWebView

UIWebView 代理有用于截獲請(qǐng)求的函數(shù),在里面做判斷就好:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSURL *url = request.URL;
    // 與約定好的函數(shù)名作比較
    if ([[url scheme] isEqualToString:@"your_func_name"]) {
        // just do it
    }
}

② WKWebView

WKWebView 有兩個(gè)代理,一個(gè)是 WKNavigationDelegate,另一個(gè)是 WKUIDelegate。WKUIDelegate 在另一篇文章中講到,這里我們需要設(shè)置并實(shí)現(xiàn)它的 WKNavigationDelegate 方法:

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSURL *url = navigationAction.request.URL;
    // 與約定好的函數(shù)名作比較
    if ([[url scheme] isEqualToString:@"your_func_name"]) {
        // just do it
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }

    decisionHandler(WKNavigationActionPolicyAllow);
}

decisionHandler 是當(dāng)你的應(yīng)用程序決定是允許還是取消導(dǎo)航時(shí),要調(diào)用的代碼塊。 該代碼塊使用單個(gè)參數(shù),它必須是枚舉類型 WKNavigationActionPolicy 的常量之一。如果不調(diào)用 decisionHandler 會(huì)引起 crash。

這里補(bǔ)充一下 JS 代碼:

function callNative() {
    loadURL("your_func_name://xxx");
}   

然后用一下就好了

b. JavaScriptCore 方法

iOS 7 有了 JavaScriptCore 專門用來做 Native 與 JS 的交互。我們可以在 webview 完成加載之后獲取 JSContext,然后利用 JSContext 將 JS 中的對(duì)象引用過來用 Native 代碼對(duì)其作出解釋或響應(yīng):

// 首先引入 JavaScriptCore 庫
#import <JavaScriptCore/JavaScriptCore.h>

// 然后再 UIWebView 的完成加載的代理方法中
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    // 獲取 JS 上下文
    jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    // 做引用,將 JS 內(nèi)的元素引用過來解釋,比如方法可以解釋成 Block,對(duì)象也可以指向 OC 的 Native 對(duì)象哦
    jsContext[@"iosDelegate"] = self;
    jsContext[@"yourFuncName"] = ^(id parameter){
        // 注意這里的線程默認(rèn)是 web 處理的線程,如果涉及主線程操作需要手動(dòng)轉(zhuǎn)到主線程
        dispatch_async(dispatch_get_main_queue(), ^{
        // your code
        });
    }
}

而 JS 這邊代碼更簡單了,干脆聲明一個(gè)不解釋的函數(shù)(約定好名字的),用于給 Native 做引用:

var parameter = xxx;
yourFuncName(parameter);
  1. iOS Native 調(diào)用 JS

iOS Native 調(diào)用 JS 的實(shí)現(xiàn)方法也被 JavaScriptCore 劃分開來:

a. webview 直接注入 JS 并執(zhí)行
b. JavaScriptCore 方法

a. webview 直接注入 JS 并執(zhí)行

在 iOS 平臺(tái),webview 有注入并執(zhí)行 JS 的 API。

UIWebView

UIWebView 有直接注入 JS 的方法:

NSString *jsStr = [NSString stringWithFormat:@"showAlert('%@')", @"alert msg"];
[_webView stringByEvaluatingJavaScriptFromString:jsStr];

這個(gè)方法會(huì)返回運(yùn)行 JS 的結(jié)果(nullable NSString *),它是一個(gè)同步方法,會(huì)阻塞當(dāng)前線程!盡管此方法不被棄用,但最佳做法是使用 WKWebView 類的 evaluateJavaScript:completionHandler:method。

WKWebView

不同于 UIWebView,WKWebView 注入并執(zhí)行 JS 的方法不會(huì)阻塞當(dāng)前線程。因?yàn)榭紤]到 webview 加載的 web content 內(nèi) JS 代碼不一定經(jīng)過驗(yàn)證,如果阻塞線程可能會(huì)掛起 App。

NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')", @"北京市東城區(qū)南鑼鼓巷納福胡同xx號(hào)"];
[_webview evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
    NSLog(@"%@----%@", result, error);
}];

這個(gè)方法不會(huì)阻塞線程,而且它的回調(diào)代碼塊總是在主線程中運(yùn)行。

b. JavaScriptCore 方法

// 首先引入 JavaScriptCore 庫
#import <JavaScriptCore/JavaScriptCore.h>

// 先獲取 JS 上下文
self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
// 如果涉及 UI 操作,切回主線程調(diào)用 JS 代碼中的 YourFuncName,通過數(shù)組@[parameter] 入?yún)?dispatch_async(dispatch_get_main_queue(), ^{
    JSValue *jsValue = self.jsContext[@"YourFuncName"];
    [jsValue callWithArguments:@[parameter]];
});

上面的代碼調(diào)用了 JS 代碼中 YourFuncName 函數(shù),并且給函數(shù)加了 @[parameter] 作為入?yún)?。這里再貼一下 JS 代碼:

function YourFuncName(arguments){
    var result = arguments;
    // do what u want to do
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容