shouldStartLoadWithRequest
,在方法中對實現定義好的URL進行攔截,攔截到後處理原生邏輯,及回調。- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
if ([request.URL.absoluteString hasSuffix:@"js_native://alert"]) {
//這個是彈框
[self alertWidthValue:request.URL.absoluteString];
//這個是回調
[webView stringByEvaluatingJavaScriptFromString:@"jsCallBackNativeMethod('我是回調')"];
}
return YES;
}
H5代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js和原生的交互</title>
</head>
<body>
<h1>js和原生的交互 調用原生彈框</h1>
<button onclick="jsCallNativeMethod()" style="border: 1px solid black">經過攔截URL彈原生彈框</button>
</body>
</html>
<script>
function jsCallNativeMethod() {
//能夠傳參數拼在後面就行
location.href = "js_native://alert";
}
//原生回調js方法
function jsCallBackNativeMethod(arguments) {
alert('原生調用js方法 傳來的參數 = ' + arguments);
}
</script>
原生回調js
[self.webView stringByEvaluatingJavaScriptFromString:@"jsCallBackNativeMethod('我是回調')"];
複製代碼
步驟:
1. 和前端約定好要傳的參數和方法名、回調方法等。
2. 實現webViewDidFinishLoad代理方法,獲取js,在裏寫實現要調用的原生方法,接收傳來的參數。
3. 利用evaluateScript執行回調html的方法
複製代碼
實現方法一:直接獲取js中定義好的方法html
- (void)webViewDidFinishLoad:(UIWebView *)webView{
JSContext *jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
__weak typeof(self) weakSelf = self;
//nativeAlert js定義的方法
jsContext[@"nativeAlert"] = ^(){
//傳來的參數
NSArray *arguments = [JSContext currentArguments];
NSLog(@"%@",arguments);
NSString *value = [NSString stringWithFormat:@"%@",[arguments objectAtIndex:0]];
[self alertWidthValue:value];
[weakSelf handleOtherOperating];
};
}
- (void)handleOtherOperating {
// 其餘處理
NSLog(@"原生處理方法 thread = %@", [NSThread currentThread]);
// 原生回調js方法
JSContext * context = [_webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
[context evaluateScript:@"nativeCallbackJscMothod('我是原生傳過去的參數')"];
}
h5代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js和原生的交互</title>
</head>
<body>
<h1>js和原生的交互 調用原生彈框</h1>
<button onclick="jscCallNativeMethod()" style="border: 1px solid black">經過JavaScriptCore實現JS原生交互</button>
</body>
</html>
<script>
function jscCallNativeMethod() {
nativeAlert('我是傳來的參數1', '我是傳來的參數2');
}
// 原生的回調方法 能夠接收原生傳來的參數
function nativeCallbackJscMothod(arguments) {
alert('原生調用js方法 傳來的參數 = ' + arguments);
}
</script>
複製代碼
實現方法二:利用JSExport協議來處理前端
步驟:
1. 在html頁面中定義須要調用原生的方法、原生回調JS的方法
2. 建立一個工具類實現一個遵照JSExport的協議,提供js須要調用的方法
3. 在webViewDidFinishLoad中利用JSContext將這個類暴露給html
複製代碼
//建立一個工具類實現一個遵照JSExport的協議,提供js須要調用的方法
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
NS_ASSUME_NONNULL_BEGIN
///建立一個遵循JSExport的協議
@protocol JSToolProtocol <NSObject,JSExport>
// 提供給js調用原生的方法,若是想暴露一些屬性也是能夠的。
- (void)jsCallNativeMethod;
@end
@interface JSTool : NSObject<JSToolProtocol>
@property (nonatomic, strong) JSContext * jsContext;
@end
NS_ASSUME_NONNULL_END
@implementation JSTool
- (void)jsCallNativeMethod {
NSLog(@"js 調用 原生方法");
// 若是還想要調用js的方法就須要拿到webView的JSContext
[self.jsContext evaluateScript:@"nativeCallbackJscMothod('原生傳遞的參數')"];
}
@end
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js和原生的交互</title>
</head>
<body>
<h1>js和原生的交互 調用原生彈框</h1>
<button onclick="jseCallNativeMethod()" style="border: 1px solid black">經過JSExport協議實現JS原生交互</button>
</body>
</html>
<script>
function jseCallNativeMethod() {
jsTool.jsCallNativeMethod();//要和工具類定義的方法同樣
}
// 原生的回調方法 能夠接收原生傳來的參數
function nativeCallbackJscMothod(arguments) {
alert('原生調用js方法 傳來的參數 = ' + arguments);
}
</script>
- (void)webViewDidFinishLoad:(UIWebView *)webView{
JSContext *jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
JSTool *jsTool = [[JSTool alloc]init];
jsTool.jsContext = jsContext;
// 方式一
// jsContext[@"jsTool"] = jsTool;
// 方式二
[jsContext setObject:jsTool forKeyedSubscript:@"jsTool"];
}
複製代碼
* WKWebViewConfiguration用來初始化WKWebView的配置。
* WKPreferences配置webView可否使用JS或者其餘插件等
* WKUserContentController用來配置JS交互的代碼
* UIDelegate用來控制WKWebView中一些彈窗的顯示(alert、confirm、prompt)。
* WKNavigationDelegate用來監聽網頁的加載狀況,包括是否容許加載,加載失敗、成功加載等一些列代理方法。
複製代碼
// 攔截URL
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL * url = navigationAction.request.URL;
NSString * scheme = url.scheme;
NSString * query = url.query;
NSString * host = url.host;
if ([[url absoluteString] hasSuffix:@"js_native://alert"]) {
[self handleJSMessage];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
- (void)handleJSMessage {
// 回調JS方法
[_wkWebView evaluateJavaScript:@"nativeCallbackJscMothod('123')" completionHandler:^(id _Nullable x, NSError * _Nullable error) {
NSLog(@"x = %@, error = %@", x, error.localizedDescription);
}];
}
#pragma mark - WKUIDelegate
// 處理JS中回調方法的alert方法 JS端調用alert()方法會觸發下面這個方法,而且經過message獲取到alert的信息
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"舒適提示" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"肯定" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alert animated:YES completion:nil];
completionHandler();
}
- (WKWebView *)wkWebView{
if (!_wkWebView) {
//初始化WKWebView的配置
WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc] init];
// 配置JS交互的代碼
configuration.userContentController = [WKUserContentController new];
// 配置webView可否使用JS或者其餘插件等
WKPreferences * preferences = [WKPreferences new];
preferences.javaScriptCanOpenWindowsAutomatically = YES;
preferences.minimumFontSize = 50.0;
configuration.preferences = preferences;
_wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_webView.frame), [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height/2) configuration:configuration];
_wkWebView.navigationDelegate = self;
_wkWebView.UIDelegate = self;
[self.view addSubview:_wkWebView];
}
return _wkWebView;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js和原生的交互</title>
</head>
<body>
<h1>js和原生的交互 調用原生彈框</h1>
<button onclick="jsCallNativeMethod()" style="border: 1px solid black">經過攔截URL彈原生彈框</button>
</body>
</html>
<script>
function jsCallNativeMethod() {
//能夠傳參數拼在後面就行
location.href = "js_native://alert";
}
// 原生的回調方法 能夠接收原生傳來的參數
function nativeCallbackJscMothod(arguments) {
alert('原生調用js方法 傳來的參數 = ' + arguments);
}
</script>
複製代碼
WKWebView不支持JavaScriptCore。此時咱們可使用WKWebView的WKScriptMessageHandler。
1. 在原生代碼中利用userContentController添加JS端須要調用的原生方法
2. 實現WKScriptMessageHandler協議中惟一一個方法`didReceiveScriptMessage`
3. 在該方法中根據message.name獲取調用的方法名作相應的處理,經過message.body獲取JS端傳遞的參數
4.在JS端經過`window.webkit.messageHandlers.methodName(事先定好的名稱).postMessage(['name','參數','age', 18])`給WK發送消息`didReceiveScriptMessage`這個方法會接收到,能夠經過`message.body`獲取傳來的值。
複製代碼
initWithFrame:configuration
初始化方法,給configuration
傳入WKWebViewConfiguration
對象,在WKWebViewConfiguration
配置和JS
交互的方法。- (WKWebView *)wkWebView{
if (!_wkWebView) {
//初始化WKWebView的配置
WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc] init];
// 配置JS交互的代碼
configuration.userContentController = [WKUserContentController new];
// MessageHandler添加對象 記得實現協議<WKScriptMessageHandler> name JS發送postMessage的對象
[configuration.userContentController addScriptMessageHandler:self name:@"jsCallNativeMethod"];
_wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(_webView.frame), [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height/2) configuration:configuration];
_wkWebView.navigationDelegate = self;
_wkWebView.UIDelegate = self;
[self.view addSubview:_wkWebView];
}
return _wkWebView;
}
複製代碼
didReceiveScriptMessage
代理方法,當js調用jsCallNativeMethod
方式時,會回調這個代理方法。#pragma mark - WKScriptMessageHandler
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
if ([message.name isEqualToString:@"jsCallNativeMethod"]) {
//這個是傳過來的參數
NSLog(@"%@",message.body);
// 回調JS方法
[_wkWebView evaluateJavaScript:@"nativeCallbackJscMothod('123')" completionHandler:^(id _Nullable x, NSError * _Nullable error) {
// NSLog(@"x = %@, error = %@", x, error.localizedDescription);
}];
}
}
複製代碼
// window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
// 這個name就是設置MessageHandler的第二個參數
function jsCallNativeMethod() {
window.webkit.messageHandlers.jsCallNativeMethod.postMessage('個人參數');
}
複製代碼
- (void)dealloc {
// 爲了不循環引用,致使控制器沒法被釋放,須要移除
[self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"jsCallNativeMethod"];
}
複製代碼
WebViewJavascriptBridge
WebViewJavascriptBridge 地址java
當前項目代碼地址git