tips:学点web技术是有必要的
UIWebView已经被苹果爸爸抛弃了下面只说WKWebView其实方法思想差不多
demo地址
基础使用
加载网页
- 导入
#import <WebKit/WebKit.h>
- 懒加载
@property(nonatomic,strong)WKWebView *webView;
- (WKWebView *)webView
{
if (!_webView) {
WKWebView *view = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:view];
_webView = view;
}
return _webView;
}
- 加载本地、网络
//网络
NSString *url = @"https://www.baidu.com";
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
//本地
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"index" ofType:@"html"];
NSURL *baseUrl = [[NSBundle mainBundle]bundleURL];
NSString *sourceString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
[self.webView loadHTMLString:sourceString baseURL:baseUrl];
Swift版本:
lazy var webView: WKWebView = {
var webView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height))
self.view.addSubview(webView)
return webView
}()
let url = "https://www.baidu.com"
webView.load(URLRequest.init(url: URL.init(string: url)!))
![](https://img.haomeiwen.com/i1943815/c4eb8ac7d779e064.png)
![](https://img.haomeiwen.com/i1943815/686f2bccf324078b.png)
代理
遵守代理 navigationDelegate,主要处理一些跳转、加载处理操作
遵守代理 UIDelegate,主要处理JS脚本,确认框,警告框等
navigationDelegate
处理 跳转、加载等
代理方法也很多 简单讲几条
- 身份验证 基本不用
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler;
公司要对接一个第三方平台,然后就有了一个可奇葩的逻辑,用户填写完相关信息后,点击提交,然后服务器返回一个网页的源代码……需要用WebView加载这个网页。实现的时候发现,我自己写的简单的网页源码可以加载,但是服务器返回的就是无法加载。后来把源码保存成文件以后,用浏览器打开发现,该网页链接的站点是一个不受信任的站点,应该是因为服务器证书无效而不受信任。
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{
NSLog(@"didReceiveAuthenticationChallenge");
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,card);
}
}
-
decidePolicyForNavigationAction、decidePolicyForNavigationResponse
请求之前是否跳转、请求响应之后是否跳转(方法会多次调用的 因为跳转就有)
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction preferences:(WKWebpagePreferences *)preferences decisionHandler:(void (^)(WKNavigationActionPolicy, WKWebpagePreferences *))decisionHandler API_AVAILABLE(macos(10.15), ios(13.0));
2个方法任取其一
typedef NS_ENUM(NSInteger, WKNavigationActionPolicy) {
WKNavigationActionPolicyCancel,
WKNavigationActionPolicyAllow,
} API_AVAILABLE(macos(10.10), ios(8.0));
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSLog(@"decidePolicyForNavigationAction");
decisionHandler(WKNavigationActionPolicyAllow);
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
NSLog(@"decidePolicyForNavigationResponse");
decisionHandler(WKNavigationResponsePolicyAllow);
}
WKNavigationActionPolicyAllow:网页可以正常跳转
WKNavigationActionPolicyCancel:取消网页跳转
此方法可以用于拦截url与web交互
获取协议、域名、完整路径、相对路径、端口、路径、search、参数
例子:
NSLog(@"scheme:%@",navigationAction.request.URL.scheme);
NSLog(@"host:%@",navigationAction.request.URL.host);
NSLog(@"absoluteString:%@",navigationAction.request.URL.absoluteString);
NSLog(@"relativePath:%@",navigationAction.request.URL.relativePath);
NSLog(@"port:%@",navigationAction.request.URL.port);
NSLog(@"path:%@",navigationAction.request.URL.path);
NSLog(@"pathComponents:%@",navigationAction.request.URL.pathComponents);
NSLog(@"query:%@",navigationAction.request.URL.query);
NSLog(@"decidePolicyForNavigationAction");
------ ViewController.m ------ 65 行 ------ scheme:https
------ ViewController.m ------ 66 行 ------ host:hqhhtest.hqhh520.cn
------ ViewController.m ------ 67 行 ------ absoluteString:https://hqhhtest.hqhh520.cn/h5/#/carRental?classId=9
------ ViewController.m ------ 68 行 ------ relativePath:/h5
------ ViewController.m ------ 69 行 ------ port:(null)
------ ViewController.m ------ 70 行 ------ path:/h5
------ ViewController.m ------ 71 行 ------ pathComponents:(
"/",
h5
)
------ ViewController.m ------ 72 行 ------ query:(null)
如果加载本地界面 不会主动调用action、response方法
- 页面开始加载、内容返回、加载完成、加载失败*
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
{
NSLog(@"didStartProvisionalNavigation");
}
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
{
NSLog(@"didCommitNavigation");
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
{
NSLog(@"didFinishNavigation");
}
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
NSLog(@"didFailNavigation");
}
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
{
//当Response响应后 不允许则会加载失败
NSLog(@"didFailProvisionalNavigation");
}
UIDelegate
处理JS脚本,确认框,警告框等
js中加弹出框代码哦
- (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:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:nil];
}
小功能
返回、前进上一个界面
if (self.webView.canGoBack) {
[self.webView goBack];
}
if (self.webView.canGoForward) {
[self.webView goForward];
}
获取标题、获取加载进度
记得销毁 dealloc 移除监听
[_webView removeObserver:self forKeyPath:@"title"];
[_webView removeObserver:self forKeyPath:@"estimatedProgress"];
[_webView.scrollView removeObserver:self forKeyPath:@"contentSize"];
- (void)addObserver
{
[self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
[self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL];
[self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
NSLog(@"keyPath:%@",keyPath);
if ([keyPath isEqualToString:@"title"]) {
self.title = self.webView.title;
} else if ([keyPath isEqualToString:@"estimatedProgress"]) {
NSLog(@"%f",self.webView.estimatedProgress);
} else if ([keyPath isEqualToString:@"contentSize"]) {
NSLog(@"%@",object);
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
交互
url重定向
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSLog(@"URL:%@",navigationAction.request.URL);
decisionHandler(WKNavigationActionPolicyAllow);
}
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
{
NSLog(@"decidePolicyForNavigationResponse");
decisionHandler(WKNavigationResponsePolicyAllow);
}
判断url
MessageHandler(原生)
拓展点configuration、userContentController
初始化设置
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
//设置偏好设置
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc]init];
// 默认是0 其实不建议在此设置的
config.preferences.minimumFontSize = 10;
// 是否支持javascript
config.preferences.javaScriptEnabled = YES;
//不通过用户交互,是否可以打开窗口
config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
点击js原生响应
为了测试:本地准备好html文件 这里的js方法 和 三方
WebViewJavaScriptBridge写法略有不同哦
为了测试:本地准备好html文件 这里的js方法 和 三方WebViewJavaScriptBridge写法略有不同哦
为了测试:本地准备好html文件 这里的js方法 和 三方WebViewJavaScriptBridge写法略有不同哦
window.webkit.messageHandlers.<name>.postMessage(<messageBody>)
![](https://img.haomeiwen.com/i1943815/37afa1c40f30d67c.png)
设置userContentController 遵守代理WKScriptMessageHandler
实现方法
WKUserContentController *userContentController = config.userContentController;
[userContentController addScriptMessageHandler:self name:@"showMobile"];
[userContentController addScriptMessageHandler:self name:@"showName"];
[userContentController addScriptMessageHandler:self name:@"showSendMsg"];
移除
WKUserContentController *controller = self.webView.configuration.userContentController;
[controller removeScriptMessageHandlerForName:@"showMobile"];
[controller removeScriptMessageHandlerForName:@"showName"];
[controller removeScriptMessageHandlerForName:@"showSendMsg"];
代理
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
NSLog(@"%@",message.body);
NSLog(@"%@",message.name);
}
原生驱动js响应 evaluateJavaScript
可以编写几个按钮 去触发
js代码
![](https://img.haomeiwen.com/i1943815/8e407fd354707861.png)
[self.webView evaluateJavaScript:@"alertMobile()" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
//JS 返回结果
NSLog(@"%@ %@",response,error);
}];
[self.webView evaluateJavaScript:@"alertName('wpp')" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
//JS 返回结果
NSLog(@"%@ %@",response,error);
}];
[self.webView evaluateJavaScript:@"alertSendMsg('wpp','20岁')" completionHandler:^(id _Nullable response, NSError * _Nullable error) {
//JS 返回结果
NSLog(@"%@ %@",response,error);
}];
WebViewJavascriptBridge(三方)
- 单独准备html文件
- 最好都是最新的库 旧的或许会崩溃
- 设置minimumFontSize是40 不然界面控件有点小
- 不能单独设置navigationDelegate代理 因为bridge需要设置该代理
- 设置属性
#import "WebViewJavascriptBridge.h"
@property(nonatomic,strong)WebViewJavascriptBridge *bridge;
self.bridge = [WebViewJavascriptBridge bridgeForWebView:self.webView];
[self.bridge setWebViewDelegate:self];
- 设置监听的webView
- (void)addRegisterHandler
{
[self.bridge registerHandler:@"scanClick" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"扫一扫 %@",data);
responseCallback(@"回调");
}];
[self.bridge registerHandler:@"locationClick" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"地址 %@",data);
responseCallback(@"回调");
}];
[self.bridge registerHandler:@"colorClick" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"改变颜色 %@",data);
responseCallback(@"回调");
}];
[self.bridge registerHandler:@"shareClick" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"分享%@",data);
responseCallback(@"回调");
}];
[self.bridge registerHandler:@"payClick" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"支付 %@",data);
responseCallback(@"回调");
}];
[self.bridge registerHandler:@"shakeClick" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"摇一摇 %@",data);
responseCallback(@"回调");
}];
[self.bridge registerHandler:@"goback" handler:^(id data, WVJBResponseCallback responseCallback) {
NSLog(@"返回 %@",data);
responseCallback(@"回调");
}];
}
- js互动
[self.bridge callHandler:@"testJSFunction" data:@"一个字符串" responseCallback:^(id responseData) {
NSLog(@"%@",responseData);
}];
小tip
预算view的高度
//避免高度不停回调
@property(nonatomic,assign)CGFloat webViewHeight;
//回调高度
@property(nonatomic,copy)void (^refreshUIBlock)(void);
if ([keyPath isEqualToString:@"contentSize"]) {
if (self.webViewHeight == self.webView.scrollView.contentSize.height) {
return;
}
self.webView.height = self.webView.scrollView.contentSize.height;
self.height = self.webView.height;
self.webViewHeight = self.webView.height;
!self.refreshUIBlock ?: self.refreshUIBlock ();
self.webViewHeight = self.webView.scrollView.contentSize.height;
}
进度条
显示不出来添加到scrollview
[self.webView.scrollView addSubview:self.progressView];
@property(nonatomic,strong)UIProgressView *progressView;
- (UIProgressView *)progressView
{
if (!_progressView) {
UIProgressView *view = [[UIProgressView alloc]initWithFrame:CGRectMake(0, 0, self.width, 0)];
[self.webView addSubview:view];
view.progressTintColor = kThemeColor;
//view.trackTintColor = [UIColor lightGrayColor];
_progressView = view;
}
return _progressView;
}
if ([keyPath isEqualToString:@"estimatedProgress"]) {
//NSLog(@"%f",self.webView.estimatedProgress);
[self.progressView setProgress:self.webView.estimatedProgress animated:YES];
self.progressView.hidden = self.webView.estimatedProgress == 1.0 ? YES : NO;
}
网友评论