如果没有接触过 JavaScript 的可以在这里看看JavaScript
菜鸟教程,我也是在上面学习的JavaScript
;
在这里以WKWebView
为主。
第一步,创建WKWebView
并配置:
-
导入头文件
#import
#import
-
delegate
-
WKWebView
对象
- (WKWebView *)wkWebview
{
if (_wkWebview == nil)
{
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
//TODO:设置偏好设置
config.preferences = [[WKPreferences alloc] init];
//1-默认为0
config.preferences.minimumFontSize = 80;
//2-JavaScript 是否可用,默认认为YES
config.preferences.javaScriptEnabled = YES;
//3-在iOS上默认为NO,表示不能自动通过窗口打开
config.preferences.javaScriptCanOpenWindowsAutomatically = YES;
config.processPool = [[WKProcessPool alloc] init];
config.userContentController = [[WKUserContentController alloc] init];
_wkWebview = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT==812?(HEIGHT - 34):HEIGHT)
configuration:config];
_wkWebview.UIDelegate = self;
_wkWebview.navigationDelegate = self;
_wkWebview.backgroundColor = [UIColor clearColor];
_wkWebview.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_wkWebview.multipleTouchEnabled = YES;
_wkWebview.autoresizesSubviews = YES;
_wkWebview.scrollView.alwaysBounceVertical = YES;
_wkWebview.allowsBackForwardNavigationGestures = YES;/**这一步是,开启侧滑返回上一历史界面**/
[self.view addSubview:_wkWebview];
}
return _wkWebview;
}
第二步、监听网页上的弹窗事件并回传信息
JavaScript
弹窗分为三种,alert警告框
,confirm确认框
,prompt提示窗
。在 Objective-C
中分别有对应的方法来接收和响应他们的操作并且回传需要的信息。
alert警告框
#pragma mark 接收网页端过来的 alert 信息
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *confirm = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
[alert addAction:confirm];
[self presentViewController:alert animated:YES completion:nil];
completionHandler();
}
confirm确认框
#pragma mark 接收确认框信息,并提交操作
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *confirm = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(YES);
}];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(NO);
}];
[alert addAction:confirm];
[alert addAction:cancel];
[self presentViewController:alert animated:YES completion:nil];
}
prompt提示窗
#pragma mark 接收网页端 prompt 信息,并提交输入内容
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:prompt preferredStyle:UIAlertControllerStyleAlert];
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
}];
UIAlertAction *confirm = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler(alert.textFields[0].text);
}];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler(@"");
}];
[alert addAction:confirm];
[alert addAction:cancel];
[self presentViewController:alert animated:YES completion:nil];
}
第三步、响应其它网页端事件,接收JavaScript
传递过来的值。
如下,html
中有一个 button
元素,它响应的JavaScript
函数为eoc()
如何在OC
端响应这个消息呢?
- 我们可以采取类似
OC
中观察者模式的方式,在eoc()
中添加window.webkit.messageHandlers.htmlAction01.postMessage('点击了第一个按钮');
来向OC
发送一条信息,具体的格式为:
window.webkit.messageHandlers.ActionObjectName.postMessage('所需传递的值或信息');
- 在
OC
中通过WKWebView
添加消息监听,具体为
//4-在这里设置监听代理,监听 JavaScript 对象的发出的信息
[config.userContentController addScriptMessageHandler:self name:@"htmlAction01"];
[config.userContentController addScriptMessageHandler:self name:@"htmlAction02"];
[config.userContentController addScriptMessageHandler:self name:@"htmlAction03"];
- 在代理方法中做出操作
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
if ([message.name isEqualToString:@"htmlAction01"]) {
NSLog(@"*01***%@***",message);
}else if ([message.name isEqualToString:@"htmlAction02"]){
NSLog(@"*02***%@***",message);
}else if ([message.name isEqualToString:@"htmlAction03"]){
NSLog(@"*03***%@***",message);
}
[self alertWithMessage:message.body];
}
第四步、JavaScript
响应OC
的消息,接收传递过来的值
- 添加新元素节点
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;
具体的使用:
NSString *jsValue = @"var ne = document.createElement('button');
var nc = document.createTextNode('后来添加的button');
ne.addEventListener('click',function(){alert('这是新添加 btn 的测试弹窗')});
ne.appendChild(nc);
document.getElementById('bby').appendChild(ne);"
[webView evaluateJavaScript:jsValue completionHandler:^(id _Nullable response, NSError * _Nullable error) {
NSLog(@"*001***** %@ *****error:%@",response,error);
}];
上面的操作会找到id
为bby
的元素,并向这个元素节点之中添加一个button
元素,同时这个button
元素会响应function(){alert('这是新添加 btn 的测试弹窗')
这个操作;
- 传值给
JavaScript
方式一:
在网页端有这样一个函数
function userLogin(isLogin){
alert(isLogin?"用户已登录":"用户未登录");
}
OC
端的操作
NSString *jsValue = [NSString stringWithFormat:@"userLogin(%d)",YES];
[self.wkWebview evaluateJavaScript: jsValue completionHandler:^(id _Nullable response, NSError * _Nullable error) {
NSLog(@"*002***** %@ *****error:%@",response,error);
}];
- 方式二
NSString *jsValue = @"confirm('{name:Tom,age:18,height:188}');";
[self.wkWebview evaluateJavaScript: jsValue completionHandler:^(id _Nullable response, NSError * _Nullable error) {
NSLog(@"*003***** %@ *****error:%@",response,error);
}];
不足的地方,还请多多指教,谢谢了。
更新:经过一位大神同学指导,
关于JavaScript
调用 原生方法
因为window.webkit.messageHandlers.ActionObjectName.postMessage('所需传递的值或信息');
只在第一次注册时有效,且可能会随着代码量的增加要注册很多个,这样就麻烦一些了。
所以,当我们想通过JavaScript
调用 原生方法且需要回传值时,可以在JavaScript
端对prompt
的参数进行封装(大神同学采取的是对prompt
封装,我暂时没有看懂他写的,就对prompt
的参数进行了封装),这样就能在不注册window.webkit.messageHandlers.ActionObjectName.postMessage('所需传递的值或信息');
的时候随时调用 原生方法。
思路:
JavaScript
端
function bridge(nativeMethod,otherParams,isNativeMethod,promptStr){
var txt = {
'nativeMethod':nativeMethod,
'otherParams':otherParams,
'isNativeMethod':isNativeMethod,
'promptStr':promptStr
};
console.log(JSON.stringify(txt));
return prompt(JSON.stringify(txt),'');
}
Objective-C
端
在原生端,可以根据isNativeMethod
参数来判断是调用原生方法,还是弹起弹窗。
nativeMethod
参数是所要调用原生方法的方法名字符串,通过NSSelectorFromString(<#NSString * _Nonnull aSelectorName#>)
转为为原生方法。
otherParams
是其它需要传递的参数。
promptStr
是弹窗的提示信息。