iOS WKWebView OC 与 JS 交互学习
我写WKWebView 想让 服务端相应 一个 方法但是不响应,根据 UIWebView 用 JSContext就能拿到响应的处理经验是不是服务端 也需要 对 WKwebView有兼容的一个写法??? 特此学习 WKWebView 记录
一 .WKWebView 代理协议
(1)WKScriptMessageHandler :
OC在JS调用方法时做的处理。如果需要调用对话窗口就会先执行(3)协议再执行 (1)协议
好处:传递给OC的参数直接在字典里面,不用再在url里面拼凑后的结果去截取解析。
必须实现
- (void)userContentController:(WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage *)message
(2)WKNavigationDelegate:
处理页面跳转和载入过程。
#pragma mark -- 进行页面跳转 // 接收到服务器跳转请求之后再执行
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation;
// 在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler ;
// 在收到响应后,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler ;
#pragma mark -- 追踪加载过程 // 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation; // 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation;
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation;
// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error; //好多协议 按需添加。。。
(3)WKUIDelegate
这个协议主要用于WKWebView处理web界面的三种提示框(警告框、确认框、输入框) 的网页交互
#pragma mark - WKUIDelegate
//警告
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
//确认
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
// 输入框
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler;
二.协议使用
(1)WKScriptMessageHandler ,关键在当前页面销毁后要注销协议保证无强引用,当前页面也无法销毁,发生内存泄漏。
//注册协议
self.userContentController = [[WKUserContentController alloc] init];
//注册方法
WKDelegateController *delegateController = [[WKDelegateController alloc]init];
delegateController.delegate = self; // 通过JS与webview内容交互
config.userContentController = self.userContentController;
// 注入JS对象名称HFAlert,HFConfirm,HFPrompt当JS通过HFAlert,HFConfirm,HFPrompt来调用时,
// 我们可以在WKScriptMessageHandler代理中接收到
[config.userContentController addScriptMessageHandler:delegateController name:HFAlert];
[config.userContentController addScriptMessageHandler:delegateController name:HFConfirm];
[config.userContentController addScriptMessageHandler:delegateController name:HFPrompt];
[config.userContentController addScriptMessageHandler:delegateController name:HFShare];
//注销协议
- (void)dealloc
{
[self.userContentController removeScriptMessageHandlerForName:HFAlert];
[self.userContentController removeScriptMessageHandlerForName:HFConfirm];
[self.userContentController removeScriptMessageHandlerForName:HFPrompt];
[self.userContentController removeScriptMessageHandlerForName:HFShare];
}
//实施协议
- (void)userContentController:(WKUserContentController *)userContentController
didReceiveScriptMessage:(WKScriptMessage *)message {
NSLog(@"%@", message.body);
if ([message.name isEqualToString:HFAlert]) {
// 打印所传过来的参数,只支持NSNumber, NSString, NSDate, NSArray,
// NSDictionary, and NSNull类型
NSDictionary *dictionary = message.body;
if (![dictionary isKindOfClass:[NSDictionary class]]) {
return;
}
NSLog(@"%@",dictionary[@"body"]); //服务端传值 log
dispatch_async(dispatch_get_main_queue(), ^{
//主线程操作UI
});
} else if ([message.name isEqualToString:HFConfirm]) { } else if ([message.name isEqualToString:HFPrompt]) { } else if ([message.name isEqualToString:HFShare]) { }
}
设置代理 WKDelegateController 重写成代理控制器性质,保证设置代理后,可移除 的关键!!!
//
// WKDelegateController.m
// SectionDemo
//
// Created by HF on 2017/6/22.
// Copyright © 2017年 HF-Liqun. All rights reserved.
// #import "WKDelegateController.h" @interface WKDelegateController () @end @implementation WKDelegateController - (void)viewDidLoad {
[super viewDidLoad];
} - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
if ([self.delegate respondsToSelector:@selector(userContentController:didReceiveScriptMessage:)]) {
[self.delegate userContentController:userContentController didReceiveScriptMessage:message];
}
}
@end
////////
//
// WKDelegateController.h
// SectionDemo
//
// Created by HF on 2017/6/22.
// Copyright © 2017年 HF-Liqun. All rights reserved.
// #import <UIKit/UIKit.h>
#import <WebKit/WebKit.h> @protocol WKDelegate <NSObject> - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message; @end @interface WKDelegateController : UIViewController <WKScriptMessageHandler> @property (weak , nonatomic) id < WKScriptMessageHandler > delegate; @end
(2)WKNavigationDelegate,举例子和UIWebView shouldStart 方法一样,在请求前判断要不要继续执行
// 在发送请求之前,决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSString *hostname = navigationAction.request.URL.host.lowercaseString;
if (navigationAction.navigationType == WKNavigationTypeLinkActivated
&& ![hostname containsString:@".baidu.com"]) {
// 对于跨域,需要手动跳转
[[UIApplication sharedApplication] openURL:navigationAction.request.URL]; // 不允许web内跳转
decisionHandler(WKNavigationActionPolicyCancel);
} else {
self.progressView.alpha = 1.0;
decisionHandler(WKNavigationActionPolicyAllow);
}
NSLog(@"%s", __FUNCTION__);
}
(3)WKUIDelegate 参考代码
#pragma mark - WKUIDelegate 这个协议主要用于WKWebView处理web界面的三种提示框(警告框、确认框、输入框) 的网页交互/**
* web界面中有弹出警告框时调用
*
* @param webView 实现该代理的webview
* @param message 警告框中的内容
* @param frame 主窗口
* @param completionHandler 警告框消失调用 无回调
*/ - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
NSLog(@"%s", __FUNCTION__);
//completionHandler(@"空回调");
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert" message:[NSString stringWithFormat:@"JS调用alert message:%@",message] preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]]; [self presentViewController:alert animated:YES completion:NULL];
NSLog(@"%@", message);
} /**
确认框 @param webView 实现该代理的webview
@param message 确认窗口内容
@param frame 主窗口
@param completionHandler 警告框消失调用 回传布尔变量
*/
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
NSLog(@"%s", __FUNCTION__); //completionHandler(@"可以直接回传布尔变量");
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"confirm" message:@"JS调用confirm" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}]];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}]];
[self presentViewController:alert animated:YES completion:NULL]; NSLog(@"%@", message);
} /**
输入框 @param webView web
@param prompt 文本
@param defaultText 默认输入文本
@param frame frame
@param completionHandler completionHandler 回传 字符串
*/
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler { //completionHandler(@"可以直接回传字符串");
//可以根据回传参数来判断 是否必要展示 弹框,也可以隐式处理 根据当前参数判断回传指定逻辑参数
NSLog(@"%s", __FUNCTION__);
NSLog(@"%@", prompt);
if ([prompt isEqualToString:HFPrompt]) {
completionHandler(@"guess");
return;
}
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS调用输入框" preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.textColor = [UIColor redColor];
}]; [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler([[alert.textFields lastObject] text]);
}]]; [self presentViewController:alert animated:YES completion:NULL];
}
三.OC JS 互相调用
(1) OC 调用 JS 代码(OC注入JS)
NSString *js = @"alertName('我是参数')";//可以向js传参数
//NSString *js = @"callJsAlert()";//无参数方法
[self.webView evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) {
NSLog(@"response: %@ error: %@", response, error);
NSLog(@"call js alert by native");
}];
(2) JS 调用 OC方法:关键是按照约定方法名和注册名
关键代码:
//name 为注册名 HFAlert HFPrompt ... messageBody 为传递参数集合 和 UIWebView的 调用OC 方法 是不一样的!!!!!
window.webkit.messageHandlers.<name>.postMessage(<messageBody>);
参考示例:
<!DOCTYPE html>
<html>
<head>
<title>iOS and Js</title>
<style type="text/css">
* {
font-size: 40px;
}
</style>
</head> <body> <div style="margin-top: 100px">
<h1>Test how to use objective-c call js</h1><br/><br/>
<div><input type="button" value="call shareButton" onclick="shareClick()"></div>
<br/><br/>
<div><input type="button" value="call js alert" onclick="callJsAlert()"></div>
<br/>
<div><input type="button" value="Call js confirm" onclick="callJsConfirm()"></div><br/>
</div>
<br/>
<div>
<div><input type="button" value="Call Js prompt " onclick="callJsInput()"></div><br/>
<div>Click me here: <a href="http://www.baidu.com">Jump to Baidu</a></div>
</div> <br/>
<div id="SwiftDiv">
<span id="jsParamFuncSpan" style="color: red; font-size: 50px;"></span>
</div> <script type="text/javascript">
//JS执行window.webkit.messageHandlers.Share.postMessage(<messageBody>)
function callJsAlert() {
//WKUIDelegate 空回调 警告框代理被触发
alert('Objective-C call js to show alert');
// HFAlert是我们所注入的对象
window.webkit.messageHandlers.HFAlert.postMessage({body: 'call js alert in js'});
} function callJsConfirm() {
//WKUIDelegate 布尔回调 选择确认框代理被触发
if (confirm('confirm', 'Objective-C call js to show confirm')) {
document.getElementById('jsParamFuncSpan').innerHTML
= 'true';
} else {
document.getElementById('jsParamFuncSpan').innerHTML
= 'false';
} //HFConfirm是我们所注入的对象
window.webkit.messageHandlers.HFConfirm.postMessage({body: 'call js confirm in js'});
} function callJsInput() {
//WKUIDelegate 字符串回调 输入框代理被触发
var response = prompt('HFPrompt', 'Please input your name:');
document.getElementById('jsParamFuncSpan').innerHTML = response; //HFPrompt是我们所注入的对象
window.webkit.messageHandlers.HFPrompt.postMessage({body: response});
} function shareClick() {
var response = prompt('Hello');
window.webkit.messageHandlers.HFShare.postMessage({body:response ,title:'测试分享的标题',content:'测试分享的内容',url:'https://github.com/maying1992'});
} function alertName(msg) {
document.getElementById('jsParamFuncSpan').innerHTML = 'name' + msg + ', nice to meet you';
}
</script>
</body>
</html>
end
参考
(1) http://www.tuicool.com/articles/qQRrMzY
(2)http://www.cocoachina.com/ios/20160906/17487.html
(3)http://www.jianshu.com/p/4fa8c4eb1316
(4)http://blog.csdn.net/u011619283/article/details/52135988
iOS WKWebView OC 与 JS 交互学习的更多相关文章
- iOS(UIWebView 和WKWebView)OC与JS交互 之二
在iOS应用的开发过程中,我们经常会使用到WebView,当我们对WebView进行操作的时候,有时会需要进行源生的操作.那么我记下来就与大家分享一下OC与JS交互. 首先先说第一种方法,并没有牵扯O ...
- OC与JS交互之WebViewJavascriptBridge
上一篇文章介绍了通过UIWebView实现了OC与JS交互的可能性及实现的原理,并且简单的实现了一个小的示例DEMO,当然也有一部分遗留问题,使用原生实现过程比较繁琐,代码难以维护.这篇文章主要介绍下 ...
- OC与JS交互之UIWebView
随着H5的强大,hybrid app已经成为当前互联网的大方向,单纯的native app和web app在某些方面显得就很劣势.关于H5的发展史,这里有一篇文章推荐给大家,今天我们来学习最基础的基于 ...
- OC与JS交互前言
OC与JS交互过程中,可能会需要使用本地image资源及html,css,js文件,这些资源应该如何被加载? 一.WebView加载HTML UIWebView提供了三个方法来加载html资源 1. ...
- OC和JS交互的三种方法
看简书上说一共有六种OC和JS交互的方法,但是前三种原理都一致,都是通过检测.拦截Url地址实现互相调用的.剩下的react native等第三方框架原理不一样,也没有去研究,下边记录我使用的三种方法 ...
- Mac Webview OC与JS交互实现
1.首先,需要定义一个JS可识别的变量(如external)用于OC与JS交互 - (void)webView:(WebView *)sender didClearWindowObject:(WebS ...
- iOS(WKWebView)OC与JS交互 之三
随着H5功能愈发的强大,没进行过混合开发的小伙们都不好意思说自己能够独立进行iOS的app开发,在iOS7操作系统下,常用的native,js交互框架有easy-js,WebViewJavascr ...
- OC与JS交互之WKWebView
上一篇文章我们使用了JavaScriptCore框架重写了之前的示例,iOS8苹果偏爱HTML5,重构了UIWebVIew,给我们带来了WKWebView,使其性能.稳定性.功能大幅度提升,也更好的支 ...
- OC与JS交互之JavaScriptCore
JavaScriptCore提供了JavaScript和Objective-C桥接的Obj-C API.JavaScriptCore提供了让我们脱离UIWebView执行JavaScript脚本的能力 ...
随机推荐
- 使用MyBatis_Generator生成Dto、Dao、Mapping
由于MyBatis属于一种半自动的ORM框架,所以主要的工作将是书写Mapping映射文件,但是由于手写映射文件很容易出错,所以查资料发现有现成的工具可以自动生成底层模型类.Dao接口类甚至Mappi ...
- Spring MVC生成PDF文件
以下示例演示如何使用Spring Web MVC框架生成PDF格式的文件.首先使用Eclipse IDE,并按照以下步骤使用Spring Web Framework开发基于动态表单的Web应用程序: ...
- CentOS 6.5 MySQL5.6.26源码安装
一.源码安装cmake工具 从mysql5.5起,mysql源码安装开始使用cmake wget http://cmake.org/files/v3.2/cmake-3.2.3.tar.gztar z ...
- 椭圆参数方程中的θ(离心角Theta)
椭圆参数方程中的离心角θ是交以其x轴对应外接圆上点的角度(或是交以其y轴对应内接圆上点的角度) 椭圆的参数程为:x=acosθy=bsinθ.M(x,y)椭圆上一点.过M作直线⊥X轴,交以O为圆心,以 ...
- python3----函数(join)
今天写python 100例时,有个题目是大致是这样的:已知输入形式是1+3+2+1,要求输出形式为1+1+2+3 一开始思路是将输入的字符串用split()函数划分成数组,在对数组进行排序,再用fo ...
- python3----转换大小写(upper lower capitalize and title)
和其他语言一样,Python为string对象提供了转换大小写的方法:upper() 和 lower().还不止这些,Python还为我们提供了首字母大写,其余小写的capitalize()方法,以及 ...
- 打印99乘法表-python
题目:如何打印出阶梯状的99乘法表? 题解: #coding:utf-8def multiplication_tables(num):#for i in range(1,10): for j in r ...
- 机器学习之猫狗大战,解决image RGB values must be in the 0..1 range.
猫狗大战是比较经典的机器学习案例,前几天体验了一番,来记录一下 1.图片准备 首先是准备训练的图片 链接:https://pan.baidu.com/s/1ht1HIuw 密码:aw9s 2.开始训练 ...
- [Oracle] - Create DB on Oracle 12c for an Application
Let's say we are going to develop a application for a bank, or any other enterprise, this applicatio ...
- :eq()中的参数详解——需要注意
:eq()的括号中的参数如果是非负数则在DOM对象中按从上到下的顺序查找指定的元素,但是,如果是是负数,则在DOM中从下向上查找指定元素. 如下实例: 如果 $("#divTag div:e ...