級別:★★☆☆☆
標籤:「iOS與JS互動」「UIWebView與JS互動」「JavaScriptCore」
作者: Xs·H
審校: QiShare團隊
先解釋下標題:“iOS與JS互動”。iOS指iOS
原生程式碼(文章只有OC
示例),JS指WEB
前端(不單指JavaScript
),互動指JS呼叫iOS
和iOS呼叫JS
。
作者將iOS與JS互動總結成了6種方式,並將逐一介紹。目錄如下:
- iOS與JS互動之UIWebView-協議攔截
- iOS與JS互動之UIWebView-JavaScriptCore框架
- iOS與JS互動之UIWebView-JSExport協議(本週五更新)
- iOS與JS互動之WKWebView-協議攔截(本週六更新)
- iOS與JS互動之WKWebView-WKJSMessageHandler(本週日更新)
- iOS與JS互動之WKWebView-WKUIDelegate(下週一更新)
本文介紹如何使用
JavaScriptCore
框架在UIWebView
上實現iOS
與JS
互動。JavaScriptCore
是Apple
在iOS7
開放的框架。它為在UITableView
上實現OC
與JS
的互動提供了更為簡單的方式。
一、JS呼叫iOS:
- 實現邏輯:點選JS的登入按鈕,JS將登入成功後的
token
資料傳遞給iOS,iOS將收到的資料展示出來。 - 實現效果:
- JS程式碼:
//! 登入按鈕
<button onclick = "login()" style = "font-size: 18px;">登入</button>
複製程式碼
//! 登入
function login() {
var token = "js_tokenString";
loginSucceed(token);
}
//! 登入成功
function loginSucceed(token) {
var action = "loginSucceed";
jsToOc(action, token);
}
//! JS呼叫OC入口
function jsToOc(action, params) {
var url = "jsToOc://" + action + "?" + params;
loadURL(url);
}
//! 載入URL
function loadURL(url) {
window.location.href = url;
}
複製程式碼
- iOS程式碼:
//! 匯入JavaScriptCore框架標頭檔案
#import <JavaScriptCore/JavaScriptCore.h>
複製程式碼
#pragma mark - UIWebViewDelegate
//! UIWebView在每次載入請求完成後會呼叫此方法
- (void)webViewDidFinishLoad:(UIWebView *)webView {
//! 獲取JS程式碼的執行環境/上下文/作用域
JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//! 監聽JS程式碼裡面的jsToOc方法(執行效果上可以理解成重寫了JS的jsToOc方法)
context[@"jsToOc"] = ^(NSString *action, NSString *params) {
dispatch_async(dispatch_get_main_queue(), ^{
[UIWebViewJavaScriptCoreController showAlertWithTitle:action message:params cancelHandler:nil];
});
};
}
複製程式碼
- 實現原理:
1、JS與iOS約定好
jsToOc
方法,作為JS呼叫iOS的入口;
2、iOS通過[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]
獲取JS程式碼的上下文JSContext
;
3、JS呼叫jsToOc
方法,iOS使用Block形式監聽(重寫)此方法context[@"jsToOc"] = ^() {}
,收到JS的呼叫請求和引數;
PS:在使用
Block
形式監聽(重寫)JS的方法的時候,不要在Block
中直接使用外部的JSValue
和JSContent
,因為JSContext
強引用Block
,Block
強引用外部變數,JSValue
又強引用JSContext
(JSValue
需要JSContext
來執行JS程式碼),會形成迴圈引用。因為JS沒有弱引用的概念,所以__weak
不會奏效,可以通過將JSValue
作為Block
內部引數和[JSContext currentContext]
的方式分別解決兩類迴圈引用的問題。
二、iOS呼叫JS:
-
實現邏輯:點選iOS的登入按鈕,iOS將登入成功後的token資料傳遞給JS,JS將收到的資料展示出來。
-
實現效果:
-
iOS程式碼:
//! 登入按鈕
UIBarButtonItem *loginBtnItem = [[UIBarButtonItem alloc] initWithTitle:@"登入" style:UIBarButtonItemStylePlain target:self action:@selector(login:)];
self.navigationItem.rightBarButtonItems = @[loginBtnItem];
複製程式碼
//! 登入方法
- (void)login:(id)sender {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
JSContext *context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//! JSContext -evaluateScript:方式呼叫JS方法
[context evaluateScript:[NSString stringWithFormat:@"ocToJs('loginSucceed', 'oc_tokenString')"]];
//! JSValue -callWithArguments:方式呼叫JS方法
// [context[@"ocToJs"] callWithArguments:@[@"loginSucceed", @"oc_tokenString"]];
});
}
複製程式碼
- JS程式碼:
//! iOS呼叫JS入口
function ocToJs(action, params) {
document.getElementById("returnValue").innerHTML = action + '?' + params;
}
複製程式碼
//! iOS呼叫JS資料顯示框
<div id = "returnValue" style = "font-size: 18px; border: 1px dotted; height: 50px;"> </div>
複製程式碼
- 實現原理:
1、iOS通過UITableView的
-valueForKeyPath:
方法獲取JSContext物件(保證在最新的JS環境中執行JS程式碼);
2、iOS通過JSContext的-evaluateScript:
方法執行一段JS程式碼ocToJs('loginSucceed', 'oc_tokenString')
;
3、JS在ocToJs
方法中將iOS傳過來的資料顯示在div
元素中。
PS:除了使用JSContext的
-evaluateScript:
方法之外,還可以先通過[context[@"ocToJs"]
獲取到JS的ocToJs
方法對應的JSValue,然後使用JSValue的-callWithArguments:
方法呼叫JS的ocToJs
方法。
- 可從QiShare的Github獲取工程原始碼
關注我們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公眾號)