iOS ~ WKWebView 页面:加载HTML或其他
2021-12-14 本文已影响0人
阳光下的叶子呵
上面的导航栏
是使用UIView写的,不是真正的 navigationBar
返回键和标题分别是一个UIButton
和UILabel
。
- 使用方法:
WKWebViewController *userAgreementVC = [[WKWebViewController alloc] init];
// HTML链接地址:
[userAgreementVC loadWebURLSring:@"https://resource.policy.html"];
// 标题title
userAgreementVC.titleStr = @"高尔夫会员用户协议";
[self.viewController.navigationController pushViewController:userAgreementVC animated:NO];
1、.h文件
// github链接:https://github.com/XFIOSXiaoFeng/WKWebView
#import "GWBaseViewController.h"
@interface WKWebViewController : GWBaseViewController
/** 是否显示Nav */
@property (nonatomic,assign) BOOL isNavHidden;
/** 左上角返回键: NO 白色(基类颜色),YES 黑色 */
@property (nonatomic,assign) BOOL isLeftReturnColor;
/** 标题 */
@property (nonatomic,strong) NSString* titleStr;
/**
加载纯外部链接网页
@param string URL地址
*/
- (void)loadWebURLSring:(NSString *)string;
/**
加载本地网页
@param string 本地HTML文件名
*/
- (void)loadWebHTMLSring:(NSString *)string;
/**
加载外部链接POST请求(注意检查 XFWKJSPOST.html 文件是否存在 )
postData请求块 注意格式:@"\"username\":\"xxxx\",\"password\":\"xxxx\""
@param string 需要POST的URL地址
@param postData post请求块
*/
- (void)POSTWebURLSring:(NSString *)string postData:(NSString *)postData;
@end
2、.m文件
//
// WKWebViewController.m
// WKWebViewOC
//
// Created by XiaoFeng on 2016/11/24.
// Copyright © 2016年 XiaoFeng. All rights reserved.
// QQ群: 384089763 欢迎加入
// github链接: https://github.com/XFIOSXiaoFeng/WKWebView
#import "WKWebViewController.h"
#import <WebKit/WKWebView.h>
#import <WebKit/WebKit.h>
typedef enum{
loadWebURLString = 0,
loadWebHTMLString,
POSTWebURLString,
}wkWebLoadType;
static void *WkwebBrowserContext = &WkwebBrowserContext;
@interface WKWebViewController ()<WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler,UINavigationControllerDelegate,UINavigationBarDelegate>
@property (nonatomic, strong) WKWebView *wkWebView;
//设置加载进度条
@property (nonatomic,strong) UIProgressView *progressView;
//仅当第一次的时候加载本地JS
@property(nonatomic,assign) BOOL needLoadJSPOST;
//网页加载的类型
@property(nonatomic,assign) wkWebLoadType loadType;
//保存的网址链接
@property (nonatomic, copy) NSString *URLString;
//保存POST请求体
@property (nonatomic, copy) NSString *postData;
//保存请求链接
@property (nonatomic)NSMutableArray* snapShotsArray;
//返回按钮
@property (nonatomic)UIBarButtonItem* customBackBarItem;
//关闭按钮
@property (nonatomic)UIBarButtonItem* closeButtonItem;
@end
@implementation WKWebViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.isNavHidden =NO;
//加载web页面
[self webViewloadURLType];
//添加到主控制器上
[self.view addSubview:self.wkWebView];
//添加进度条
[self.view addSubview:self.progressView];
//添加右边刷新按钮
UIBarButtonItem *roadLoad = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(roadLoadClicked)];
self.navigationItem.rightBarButtonItem = roadLoad;
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
if (_isNavHidden == YES) {
self.navigationController.navigationBarHidden = YES;
//创建一个高20的假状态栏
UIView *statusBarView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 20)];
//设置成绿色
statusBarView.backgroundColor=[UIColor whiteColor];
// 添加到 navigationBar 上
[self.view addSubview:statusBarView];
}else{
self.navigationController.navigationBarHidden = NO;
}
}
- (void)roadLoadClicked{
[self.wkWebView reload];
}
-(void)customBackItemClicked{
if (self.wkWebView.goBack) {
[self.wkWebView goBack];
}else{
[self.navigationController popViewControllerAnimated:YES];
}
}
-(void)closeItemClicked{
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark ================ 加载方式 ================
- (void)webViewloadURLType{
switch (self.loadType) {
case loadWebURLString:{
//创建一个NSURLRequest 的对象
NSURLRequest * Request_zsj = [NSURLRequest requestWithURL:[NSURL URLWithString:self.URLString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
//加载网页
[self.wkWebView loadRequest:Request_zsj];
break;
}
case loadWebHTMLString:{
[self loadHostPathURL:self.URLString];
break;
}
case POSTWebURLString:{
// JS发送POST的Flag,为真的时候会调用JS的POST方法
self.needLoadJSPOST = YES;
//POST使用预先加载本地JS方法的html实现,请确认WKJSPOST存在
[self loadHostPathURL:@"WKJSPOST"];
break;
}
}
}
- (void)loadHostPathURL:(NSString *)url{
//获取JS所在的路径
NSString *path = [[NSBundle mainBundle] pathForResource:url ofType:@"html"];
//获得html内容
NSString *html = [[NSString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
//加载js
[self.wkWebView loadHTMLString:html baseURL:[[NSBundle mainBundle] bundleURL]];
}
// 调用JS发送POST请求
- (void)postRequestWithJS {
// 拼装成调用JavaScript的字符串
NSString *jscript = [NSString stringWithFormat:@"post('%@',{%@});", self.URLString, self.postData];
// 调用JS代码
[self.wkWebView evaluateJavaScript:jscript completionHandler:^(id object, NSError * _Nullable error) {
}];
}
- (void)loadWebURLSring:(NSString *)string{
self.URLString = string;
self.loadType = loadWebURLString;
}
- (void)loadWebHTMLSring:(NSString *)string{
self.URLString = string;
self.loadType = loadWebHTMLString;
}
- (void)POSTWebURLSring:(NSString *)string postData:(NSString *)postData{
self.URLString = string;
self.postData = postData;
self.loadType = POSTWebURLString;
}
#pragma mark ================ 自定义返回/关闭按钮 ================
-(void)updateNavigationItems{
if (self.wkWebView.canGoBack) {
UIBarButtonItem *spaceButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
spaceButtonItem.width = -6.5;
[self.navigationItem setLeftBarButtonItems:@[spaceButtonItem,self.customBackBarItem,self.closeButtonItem] animated:NO];
}else{
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
[self.navigationItem setLeftBarButtonItems:@[self.customBackBarItem]];
}
}
//请求链接处理
-(void)pushCurrentSnapshotViewWithRequest:(NSURLRequest*)request{
// NSLog(@"push with request %@",request);
NSURLRequest* lastRequest = (NSURLRequest*)[[self.snapShotsArray lastObject] objectForKey:@"request"];
//如果url是很奇怪的就不push
if ([request.URL.absoluteString isEqualToString:@"about:blank"]) {
// NSLog(@"about blank!! return");
return;
}
//如果url一样就不进行push
if ([lastRequest.URL.absoluteString isEqualToString:request.URL.absoluteString]) {
return;
}
UIView* currentSnapShotView = [self.wkWebView snapshotViewAfterScreenUpdates:YES];
[self.snapShotsArray addObject:
@{@"request":request,@"snapShotView":currentSnapShotView}];
}
#pragma mark ================ WKNavigationDelegate ================
//这个是网页加载完成,导航的变化
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
/*
主意:这个方法是当网页的内容全部显示(网页内的所有图片必须都正常显示)的时候调用(不是出现的时候就调用),,否则不显示,或则部分显示时这个方法就不调用。
*/
// 判断是否需要加载(仅在第一次加载)
if (self.needLoadJSPOST) {
// 调用使用JS发送POST请求的方法
[self postRequestWithJS];
// 将Flag置为NO(后面就不需要加载了)
self.needLoadJSPOST = NO;
}
// 获取加载网页的标题
self.titleLabel.text = self.titleStr;
if (self.isLeftReturnColor) {
[self.leftButton setImage:[UIImage imageNamed:@"web_back"] forState:UIControlStateNormal];
}
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
// [self updateNavigationItems];
}
//开始加载
-(void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
//开始加载的时候,让加载进度条显示
self.progressView.hidden = NO;
}
//内容返回时调用
-(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{}
//服务器请求跳转的时候调用
-(void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation{}
//服务器开始请求的时候调用
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
switch (navigationAction.navigationType) {
case WKNavigationTypeLinkActivated: {
[self pushCurrentSnapshotViewWithRequest:navigationAction.request];
break;
}
case WKNavigationTypeFormSubmitted: {
[self pushCurrentSnapshotViewWithRequest:navigationAction.request];
break;
}
case WKNavigationTypeBackForward: {
break;
}
case WKNavigationTypeReload: {
break;
}
case WKNavigationTypeFormResubmitted: {
break;
}
case WKNavigationTypeOther: {
[self pushCurrentSnapshotViewWithRequest:navigationAction.request];
break;
}
default: {
break;
}
}
[self updateNavigationItems];
decisionHandler(WKNavigationActionPolicyAllow);
}
// 内容加载失败时候调用
-(void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error{
NSLog(@"页面加载超时");
}
//跳转失败的时候调用
-(void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{}
//进度条
-(void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{}
#pragma mark ================ WKUIDelegate ================
// 获取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:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:NULL];
}
// js 信息的交流
-(void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:message 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];
}
// 交互。可输入的文本。
-(void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
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];
}
//KVO监听进度条
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && object == self.wkWebView) {
[self.progressView setAlpha:1.0f];
BOOL animated = self.wkWebView.estimatedProgress > self.progressView.progress;
[self.progressView setProgress:self.wkWebView.estimatedProgress animated:animated];
// Once complete, fade out UIProgressView
if(self.wkWebView.estimatedProgress >= 1.0f) {
[UIView animateWithDuration:0.3f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.progressView setAlpha:0.0f];
} completion:^(BOOL finished) {
[self.progressView setProgress:0.0f animated:NO];
}];
}
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark ================ WKScriptMessageHandler ================
//拦截执行网页中的JS方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{
//服务器固定格式写法 window.webkit.messageHandlers.名字.postMessage(内容);
//客户端写法 message.name isEqualToString:@"名字"]
if ([message.name isEqualToString:@"WXPay"]) {
NSLog(@"%@", message.body);
//调用微信支付方法
// [self WXPayWithParam:message.body];
}
}
#pragma mark ================ 懒加载 ================
- (WKWebView *)wkWebView{
if (!_wkWebView) {
//设置网页的配置文件
WKWebViewConfiguration * Configuration = [[WKWebViewConfiguration alloc]init];
//允许视频播放
Configuration.allowsAirPlayForMediaPlayback = YES;
// 允许在线播放
Configuration.allowsInlineMediaPlayback = YES;
// 允许可以与网页交互,选择视图
Configuration.selectionGranularity = YES;
// web内容处理池
Configuration.processPool = [[WKProcessPool alloc] init];
//自定义配置,一般用于 js调用oc方法(OC拦截URL中的数据做自定义操作)
WKUserContentController * UserContentController = [[WKUserContentController alloc]init];
// 添加消息处理,注意:self指代的对象需要遵守WKScriptMessageHandler协议,结束时需要移除
[UserContentController addScriptMessageHandler:self name:@"WXPay"];
// 是否支持记忆读取
Configuration.suppressesIncrementalRendering = YES;
// 允许用户更改网页的设置
Configuration.userContentController = UserContentController;
_wkWebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, k_Height_NavBar, SCREEN_WIDTH, SCREEN_HEIGHT) configuration:Configuration];
_wkWebView.backgroundColor = [UIColor colorWithRed:240.0/255 green:240.0/255 blue:240.0/255 alpha:1.0];
// 设置代理
_wkWebView.navigationDelegate = self;
_wkWebView.UIDelegate = self;
//kvo 添加进度监控
[_wkWebView addObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) options:0 context:WkwebBrowserContext];
//开启手势触摸
_wkWebView.allowsBackForwardNavigationGestures = YES;
// 设置 可以前进 和 后退
//适应你设定的尺寸
[_wkWebView sizeToFit];
}
return _wkWebView;
}
-(UIBarButtonItem*)customBackBarItem{
if (!_customBackBarItem) {
UIImage* backItemImage = [[UIImage imageNamed:@"backItemImage"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIImage* backItemHlImage = [[UIImage imageNamed:@"backItemImage-hl"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
UIButton* backButton = [[UIButton alloc] init];
[backButton setTitle:@"返回" forState:UIControlStateNormal];
[backButton setTitleColor:self.navigationController.navigationBar.tintColor forState:UIControlStateNormal];
[backButton setTitleColor:[self.navigationController.navigationBar.tintColor colorWithAlphaComponent:0.5] forState:UIControlStateHighlighted];
[backButton.titleLabel setFont:[UIFont systemFontOfSize:17]];
[backButton setImage:backItemImage forState:UIControlStateNormal];
[backButton setImage:backItemHlImage forState:UIControlStateHighlighted];
[backButton sizeToFit];
[backButton addTarget:self action:@selector(customBackItemClicked) forControlEvents:UIControlEventTouchUpInside];
_customBackBarItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
}
return _customBackBarItem;
}
- (UIProgressView *)progressView{
if (!_progressView) {
_progressView = [[UIProgressView alloc]initWithProgressViewStyle:UIProgressViewStyleDefault];
if (_isNavHidden == YES) {
_progressView.frame = CGRectMake(0, 20, self.view.bounds.size.width, 3);
}else{
_progressView.frame = CGRectMake(0, k_Height_NavBar, self.view.bounds.size.width, 3);
}
// 设置进度条的色彩
[_progressView setTrackTintColor:[UIColor colorWithRed:240.0/255 green:240.0/255 blue:240.0/255 alpha:1.0]];
_progressView.progressTintColor = [UIColor greenColor];
}
return _progressView;
}
-(UIBarButtonItem*)closeButtonItem{
if (!_closeButtonItem) {
_closeButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"关闭" style:UIBarButtonItemStylePlain target:self action:@selector(closeItemClicked)];
}
return _closeButtonItem;
}
-(NSMutableArray*)snapShotsArray{
if (!_snapShotsArray) {
_snapShotsArray = [NSMutableArray array];
}
return _snapShotsArray;
}
-(void)viewWillDisappear:(BOOL)animated{
[self.wkWebView.configuration.userContentController removeScriptMessageHandlerForName:@"WXPay"];
[self.wkWebView setNavigationDelegate:nil];
[self.wkWebView setUIDelegate:nil];
}
//注意,观察的移除
-(void)dealloc{
[self.wkWebView removeObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
}
@end