一、版本
8系统前,用UIWebView
8系统后,用webkit,WKWebView
因为webkit有两大优点:
1、占用内存更小,
2、可以通过回调直接捕捉网页上的alert,输入等js操作
二、代码
第一部分:UIViewController
//
// ViewController.m
// WKWebView
//
// Created by nnandzc on 16/11/6.
// Copyright © 2016 年 nnandzc. All rights reserved.
//
#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import <WebKit/WebKit.h>
@interface ViewController ()
<
WKUIDelegate ,
WKNavigationDelegate ,
WKScriptMessageHandler
>
@property ( nonatomic , strong ) WKWebView *webView;
@property ( nonatomic , strong , readonly ) JSContext *jsContext;
@end
@implementation ViewController
- ( void )viewDidLoad {
[ super viewDidLoad ];
[ self webView ];
}
- ( WKWebView *)webView
{
if (! _webView )
{
// js 配置
WKUserContentController *userContentController = [[ WKUserContentController alloc ] init ];
[userContentController addScriptMessageHandler : self name : @"jsCallOC" ];
// WKWebView 的配置
WKWebViewConfiguration *configuration = [[ WKWebViewConfiguration alloc ] init ];
configuration. userContentController = userContentController;
_webView = [[ WKWebView alloc ] initWithFrame : self . view . bounds configuration :configuration];
_webView . navigationDelegate = self ;
_webView . UIDelegate = self ;
[ _webView addObserver : self forKeyPath : @"estimatedProgress" options : NSKeyValueObservingOptionNew context : nil ];
NSString *path = [[ NSBundle mainBundle ] bundlePath ];
NSURL *baseURL = [ NSURL fileURLWithPath :path];
NSString * htmlPath = [[ NSBundle mainBundle ] pathForResource : @"index1"
ofType : @"html" ];
NSString * htmlCont = [ NSString stringWithContentsOfFile :htmlPath
encoding : NSUTF8StringEncoding
error : nil ];
[ self . webView loadHTMLString :htmlCont baseURL :baseURL];
// [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
[ self . view addSubview : _webView ];
}
return _webView ;
}
-( void )observeValueForKeyPath:( NSString *)keyPath ofObject:( id )object change:( NSDictionary < NSString *, id > *)change context:( void *)context
{
if (object == _webView && [keyPath isEqualToString : @"estimatedProgress" ] ) {
// 这里就不写进度条了,把加载的进度打印出来,进度条可以自己加上去!
CGFloat newProgress = [[change objectForKey : NSKeyValueChangeNewKey ] floatValue ];
NSLog ( @"%f" ,newProgress);
}
}
// 页面开始加载时调用
- ( void )webView:( WKWebView *)webView didStartProvisionalNavigation:( WKNavigation *)navigation
{
// NSLog(@"%s", __func__);
}
// 当内容开始返回时调用
- ( void )webView:( WKWebView *)webView didCommitNavigation:( WKNavigation *)navigation
{
// NSLog(@"%s", __func__);
}
// 页面加载完成之后调用
- ( void )webView:( WKWebView *)webView didFinishNavigation:( WKNavigation *)navigation
{
// _jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
[ _webView evaluateJavaScript : @"navigator.userAgent" completionHandler :^( id _Nullable string, NSError * _Nullable error) {
NSLog ( @"string = %@" , string);
}];
}
// 页面加载失败时调用
- ( void )webView:( WKWebView *)webView didFailProvisionalNavigation:( WKNavigation *)navigation
{
// NSLog(@"%s", __func__);
}
// 接收到服务器跳转请求之后调用
- ( void )webView:( WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:( WKNavigation *)navigation
{
// NSLog(@"%s", __func__);
}
// 在收到响应后,决定是否跳转
- ( void )webView:( WKWebView *)webView decidePolicyForNavigationResponse:( WKNavigationResponse *)navigationResponse decisionHandler:( void (^)( WKNavigationResponsePolicy ))decisionHandler
{
// NSLog(@"%s", __func__);
decisionHandler( WKNavigationResponsePolicyAllow );
}
// 在发送请求之前,决定是否跳转
- ( void )webView:( WKWebView *)webView decidePolicyForNavigationAction:( WKNavigationAction *)navigationAction decisionHandler:( void (^)( WKNavigationActionPolicy ))decisionHandler
{
// NSLog(@"%s", __func__);
decisionHandler( WKNavigationActionPolicyAllow );
}
-( void )webView:( WKWebView *)webView runJavaScriptAlertPanelWithMessage:( NSString *)message initiatedByFrame:( WKFrameInfo *)frame completionHandler:( void (^)( void ))completionHandler
{
UIAlertController *alert = [ UIAlertController alertControllerWithTitle : @"alert" message : @"JS 调用 alert" preferredStyle : UIAlertControllerStyleAlert ];
[alert addAction :[ UIAlertAction actionWithTitle : @" 确定 " style : UIAlertActionStyleDefault handler :^( UIAlertAction * _Nonnull action) {
}]];
[ self presentViewController :alert animated : YES completion : NULL ];
completionHandler();
NSLog ( @"%@" , message);
}
-( void )webView:( WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:( NSString *)prompt defaultText:( NSString *)defaultText initiatedByFrame:( WKFrameInfo *)frame completionHandler:( void (^)( NSString * _Nullable ))completionHandler
{
}
-( void )webView:( WKWebView *)webView runJavaScriptConfirmPanelWithMessage:( NSString *)message initiatedByFrame:( WKFrameInfo *)frame completionHandler:( void (^)( BOOL ))completionHandler
{
}
@end
// ViewController.m
// WKWebView
//
// Created by nnandzc on 16/11/6.
// Copyright © 2016 年 nnandzc. All rights reserved.
//
#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import <WebKit/WebKit.h>
@interface ViewController ()
<
WKUIDelegate ,
WKNavigationDelegate ,
WKScriptMessageHandler
>
@property ( nonatomic , strong ) WKWebView *webView;
@property ( nonatomic , strong , readonly ) JSContext *jsContext;
@end
@implementation ViewController
- ( void )viewDidLoad {
[ super viewDidLoad ];
[ self webView ];
}
- ( WKWebView *)webView
{
if (! _webView )
{
// js 配置
WKUserContentController *userContentController = [[ WKUserContentController alloc ] init ];
[userContentController addScriptMessageHandler : self name : @"jsCallOC" ];
// WKWebView 的配置
WKWebViewConfiguration *configuration = [[ WKWebViewConfiguration alloc ] init ];
configuration. userContentController = userContentController;
_webView = [[ WKWebView alloc ] initWithFrame : self . view . bounds configuration :configuration];
_webView . navigationDelegate = self ;
_webView . UIDelegate = self ;
[ _webView addObserver : self forKeyPath : @"estimatedProgress" options : NSKeyValueObservingOptionNew context : nil ];
NSString *path = [[ NSBundle mainBundle ] bundlePath ];
NSURL *baseURL = [ NSURL fileURLWithPath :path];
NSString * htmlPath = [[ NSBundle mainBundle ] pathForResource : @"index1"
ofType : @"html" ];
NSString * htmlCont = [ NSString stringWithContentsOfFile :htmlPath
encoding : NSUTF8StringEncoding
error : nil ];
[ self . webView loadHTMLString :htmlCont baseURL :baseURL];
// [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
[ self . view addSubview : _webView ];
}
return _webView ;
}
-( void )observeValueForKeyPath:( NSString *)keyPath ofObject:( id )object change:( NSDictionary < NSString *, id > *)change context:( void *)context
{
if (object == _webView && [keyPath isEqualToString : @"estimatedProgress" ] ) {
// 这里就不写进度条了,把加载的进度打印出来,进度条可以自己加上去!
CGFloat newProgress = [[change objectForKey : NSKeyValueChangeNewKey ] floatValue ];
NSLog ( @"%f" ,newProgress);
}
}
// 页面开始加载时调用
- ( void )webView:( WKWebView *)webView didStartProvisionalNavigation:( WKNavigation *)navigation
{
// NSLog(@"%s", __func__);
}
// 当内容开始返回时调用
- ( void )webView:( WKWebView *)webView didCommitNavigation:( WKNavigation *)navigation
{
// NSLog(@"%s", __func__);
}
// 页面加载完成之后调用
- ( void )webView:( WKWebView *)webView didFinishNavigation:( WKNavigation *)navigation
{
// _jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
[ _webView evaluateJavaScript : @"navigator.userAgent" completionHandler :^( id _Nullable string, NSError * _Nullable error) {
NSLog ( @"string = %@" , string);
}];
}
// 页面加载失败时调用
- ( void )webView:( WKWebView *)webView didFailProvisionalNavigation:( WKNavigation *)navigation
{
// NSLog(@"%s", __func__);
}
// 接收到服务器跳转请求之后调用
- ( void )webView:( WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:( WKNavigation *)navigation
{
// NSLog(@"%s", __func__);
}
// 在收到响应后,决定是否跳转
- ( void )webView:( WKWebView *)webView decidePolicyForNavigationResponse:( WKNavigationResponse *)navigationResponse decisionHandler:( void (^)( WKNavigationResponsePolicy ))decisionHandler
{
// NSLog(@"%s", __func__);
decisionHandler( WKNavigationResponsePolicyAllow );
}
// 在发送请求之前,决定是否跳转
- ( void )webView:( WKWebView *)webView decidePolicyForNavigationAction:( WKNavigationAction *)navigationAction decisionHandler:( void (^)( WKNavigationActionPolicy ))decisionHandler
{
// NSLog(@"%s", __func__);
decisionHandler( WKNavigationActionPolicyAllow );
}
-( void )webView:( WKWebView *)webView runJavaScriptAlertPanelWithMessage:( NSString *)message initiatedByFrame:( WKFrameInfo *)frame completionHandler:( void (^)( void ))completionHandler
{
UIAlertController *alert = [ UIAlertController alertControllerWithTitle : @"alert" message : @"JS 调用 alert" preferredStyle : UIAlertControllerStyleAlert ];
[alert addAction :[ UIAlertAction actionWithTitle : @" 确定 " style : UIAlertActionStyleDefault handler :^( UIAlertAction * _Nonnull action) {
}]];
[ self presentViewController :alert animated : YES completion : NULL ];
completionHandler();
NSLog ( @"%@" , message);
}
-( void )webView:( WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:( NSString *)prompt defaultText:( NSString *)defaultText initiatedByFrame:( WKFrameInfo *)frame completionHandler:( void (^)( NSString * _Nullable ))completionHandler
{
}
-( void )webView:( WKWebView *)webView runJavaScriptConfirmPanelWithMessage:( NSString *)message initiatedByFrame:( WKFrameInfo *)frame completionHandler:( void (^)( BOOL ))completionHandler
{
}
@end
第二部分:
index1.js
function
hello(){
alert( "hello" );
}
alert( "hello" );
}
第三部分:index1.css
#p{
color : red ;
}
#img{
width : 120 px ;
height : 50 px ;
}
#a{
color : yellow ;
}
color : red ;
}
#img{
width : 120 px ;
height : 50 px ;
}
#a{
color : yellow ;
}
第四部分:index1.html
<!DOCTYPE html>
<html>
<head lang = "zh" >
<meta charset = "UTF-8" >
<title> 第一个 HTML </title>
<link rel = "stylesheet" type = "text/css" href = "index1.css" >
<script type = "text/javascript" src = "index1.js" ></script>
</head>
<body>
<h1> 我是 HTML </h1>
<p id = "p" > p 标签 </p>
<img id = "img" src = "image.png" alt = " 百度 LOGO" ><br/>
<a id = "a" href = "[http://baidu.com]()" > 我要到百度 </a>
<br/><br/><br/>
<button onclick = "hello()" > 点击我弹出 hello </button>
<input type = "button" value = " 测试 log" onclick = "activityList({'tytyty':'hehe'})" />
</body>
</html>
<html>
<head lang = "zh" >
<meta charset = "UTF-8" >
<title> 第一个 HTML </title>
<link rel = "stylesheet" type = "text/css" href = "index1.css" >
<script type = "text/javascript" src = "index1.js" ></script>
</head>
<body>
<h1> 我是 HTML </h1>
<p id = "p" > p 标签 </p>
<img id = "img" src = "image.png" alt = " 百度 LOGO" ><br/>
<a id = "a" href = "[http://baidu.com]()" > 我要到百度 </a>
<br/><br/><br/>
<button onclick = "hello()" > 点击我弹出 hello </button>
<input type = "button" value = " 测试 log" onclick = "activityList({'tytyty':'hehe'})" />
</body>
</html>
三、总结:以上代码解决了
1、网页、自定义html内容加载
2、加载过程中的回调操作
3、对于已经webkit已经替我们做好事件响应链的几个操作的回调:网页弹出alert,网页输入文字等
4、如果想通过web端调用OC端,则通过WKNavigation中的request属性,截获到服务端的请求,客户端可以和服务端约定好字符串,截获到这一段字符串时,客户端就可以为匹配字符串定义操作。参数也可以通过字符串传递给客户端
5、获取网页元素属性,和UIWebView一样,也是执行一个类似evaluateJavascript的方法,只不过WKWebView是block形式的,UIWebView是返回值形式的