iOS开发 - WKWebView

1859399-5d22b815aba81baf.png

JS 与OC 交互的方式有哪些?

1、在JS 中做一次URL跳转,然后在OC中拦截跳转。(这里分为UIWebView 和 WKWebView两种);
2、利用WKWebView 的 MessageHandler(WKWebView 是 iOS8推出的);
3、利用系统库 JavaScriptCore 来和UIWebView做相互调用(JavaScriptCore iOS 7推出的);
4、利用第三方库WebViewJavascriptBridge;
5、利用第三方cordova库,以前叫PhoneGap(这是一个库平台的库);
JS_OC

JS与OC交互 - URL拦截

iOS下JS与OC互相调用(一)--UIWebView 拦截URL
iOS下JS与OC互相调用(二)--WKWebView 拦截URL

JS与OC交互 - 利用WKWebView的MessageHandler

iOS下JS与OC互相调用(三)--WKWebView的MessageHandler

JS与OC交互 - UIWebView与系统库JavaScriptCore

iOS下JS与OC互相调用(四)--UIWebView与JavaScriptCore

JS与OC交互 - 第三方库WebViewJavascriptBridge

iOS下JS与OC互相调用(五)--UIWebView + WebViewJavascriptBridge
iOS下JS与OC互相调用(六)--WKWebView + WebViewJavascriptBridge

JS与OC交互 - 第三方cordova库

iOS下JS与OC互相调用(七)--Cordova 基础
iOS下JS与OC互相调用(八)--Cordova详解+实战

1859399-625785c28aec792e.png

WKWebView相关API介绍

WKWebView
@interface WKWebView : UIView
Starting in iOS 8.0 and OS X 10.10, use WKWebView to add web content to your app. Do not use UIWebView or WebView.


// 初始化webview相关API
// 拷贝一个configuration来初始化一个网页使用。它是一个属性的集合,这个集合用来初始化网页。
@property(nonatomic, readonly, copy) WKWebViewConfiguration *configuration;
// 初始化一个网页视图,设置其大小和配置
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration;
// 从解档数据获取一个初始化的对象。
- (nullable instancetype)initWithCoder:(NSCoder *)coder;


// 查看webview信息相关API
// WKWebView继承自UIView, 所以如果想设置scrollView的一些属性, 需要对此属性进行配置
@property (nonatomic, readonly, strong) UIScrollView *scrollView;
// 页面标题, 一般使用KVO动态获取
@property (nullable, nonatomic, readonly, copy) NSString *title;
// 当前请求的URL,支持KVO的
@property (nullable, nonatomic, readonly, copy) NSURL *URL;
// 自定义UserAgent, 会覆盖默认的值      API_AVAILABLE(macosx(10.11), ios(9.0))
@property (nullable, nonatomic, copy) NSString *customUserAgent;
// 当前提交的导航的SecTrustRef对象,支持KVO。       API_AVAILABLE(macosx(10.12), ios(10.0))
@property (nonatomic, readonly, nullable) SecTrustRef serverTrust;


// 两个delegaete
// The web view's navigation delegate.
@property (nullable, nonatomic, weak) id <WKNavigationDelegate> navigationDelegate;
// The web view's user interface delegate.
@property (nullable, nonatomic, weak) id <WKUIDelegate> UIDelegate;


// 加载content相关API
// 页面加载进度, 一般使用KVO动态获取
@property (nonatomic, readonly) double estimatedProgress;
// 标识页面中的所有资源是否通过安全加密连接来加载,支持KVO的
@property (nonatomic, readonly) BOOL hasOnlySecureContent;
// 当前是否在加载内容
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
// 重新加载当前页面。
- (nullable WKNavigation *)reload;
// 重新加载当前页面,如果可能,使用缓存验证条件执行端到端重新验证。
- (nullable WKNavigation *)reloadFromOrigin;
// 停止加载当前页面上的所有资源。
- (void)stopLoading;
// 加载请求API
- (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
// 加载URL     API_AVAILABLE(macosx(10.11), ios(9.0))
- (nullable WKNavigation *)loadFileURL:(NSURL *)URL allowingReadAccessToURL:(NSURL *)readAccessURL;
// 直接加载HTML
- (nullable WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
// 直接加载data     API_AVAILABLE(macosx(10.11), ios(9.0))
- (nullable WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL;


// Scaling Content 缩放相关API
#if !TARGET_OS_IPHONE
// 标识是否支持放大手势,默认为NO
@property (nonatomic) BOOL allowsMagnification;
// 放大因子,默认为1
@property (nonatomic) CGFloat magnification;
// 根据设置的缩放因子来缩放页面,并居中显示结果在指定的点
- (void)setMagnification:(CGFloat)magnification centeredAtPoint:(CGPoint)point;
#endif


// 导航相关API
// 标识是否支持左、右swipe手势是否可以前进、后退
@property (nonatomic) BOOL allowsBackForwardNavigationGestures;
// 是个WKBackForwardList对象,记录网页中跳转的记录
@property (nonatomic, readonly, strong) WKBackForwardList *backForwardList;
//  是否可以招待goback操作,它是支持KVO的
@property (nonatomic, readonly) BOOL canGoBack;
// 是否可以执行gofarward操作,支持KVO
@property (nonatomic, readonly) BOOL canGoForward;
// 返回上一页面,如果不能返回,则什么也不干
- (nullable WKNavigation *)goBack;
// 进入下一页面,如果不能前进,则什么也不干
- (nullable WKNavigation *)goForward;
/* 前进/后退到一个指定的记录上
item必须是WebView的WKBackForwardList中的一个记录
返回一个新的WKNavigation对象
如果已经在当前记录,或者没有找到,则会返回nil
*/ 
- (nullable WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;
/*  API_AVAILABLE(macosx(10.11), ios(9.0))
在iOS上,这个属性只在支持3D Touch的设备上支持
在iOS 10及以后的系统版本默认值是YES,之前的默认值是NO
如果将该属性的值设置为YES,则iOS用户可以按下链接来预览链接,并可以检测到地址和电话号码等数据。这样的预览被用户称为peeks
如果用户在链接预览上更深入地按下,预览将pop到目标网址。该动作会将应用程序切换到Safari
如果您想在iOS中支持链接预览,但又想要在应用程序中保留用户,那么您可以将WKWebView类转换为SFSafariViewController类
如果您使用WebView作为应用内浏览器,那么进行这种更改是最佳选择
SFSafariViewController自动支持链接预览
iOS 10.0+开始支持自定义链接预览,你也可以通过这种方式来实现用户预览网页并pop后仍然留在应用内而不用切换到Safari,只是你需要做一些额外的适配工作
*/
@property (nonatomic) BOOL allowsLinkPreview;


// 执行JavaScript
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler;


// 截屏
#if TARGET_OS_IPHONE
- (void)takeSnapshotWithConfiguration:(nullable WKSnapshotConfiguration *)snapshotConfiguration completionHandler:(void (^)(UIImage * _Nullable snapshotImage, NSError * _Nullable error))completionHandler API_AVAILABLE(ios(11.0));
WKWebViewConfiguration

WKWebViewConfiguration只会在webview第一次初始化的时候使用,你不能用此类来改变一个已经初始化完成的webview的配置。

// OC与JS交互使用,通过此属性来执行JavaScript代码来修改页面的行为
@property (nonatomic, strong) WKUserContentController *userContentController;

//***********下面属性一般不需要设置
// 首选项设置,  
//可设置最小字号, 是否允许执行js
//是否通过js自动打开新的窗口
@property (nonatomic, strong) WKPreferences *preferences;
// 是否允许播放媒体文件
@property (nonatomic) BOOL allowsAirPlayForMediaPlayback
// 需要用户来操作才能播放的多媒体类型
@property (nonatomic) WKAudiovisualMediaTypes mediaTypesRequiringUserActionForPlayback
// 是使用h5的视频播放器在线播放, 还是使用原生播放器全屏播放
@property (nonatomic) BOOL allowsInlineMediaPlayback;
......
WKUserContentController

WKUserContentControllerJavaScript与原生进行交互的桥梁, 主要使用的方法有:

// 注入JavaScript与原生交互协议
// JS 端可通过 window.webkit.messageHandlers.<name>.postMessage(<messageBody>) 发送消息
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name;
// 移除注入的协议, 在deinit方法中调用
- (void)removeScriptMessageHandlerForName:(NSString *)name;

// 通过WKUserScript注入需要执行的JavaScript代码
- (void)addUserScript:(WKUserScript *)userScript;
// 移除所有注入的JavaScript代码
- (void)removeAllUserScripts;
......

使用WKUserContentController注入的交互协议, 需要遵循WKScriptMessageHandler协议, 在其协议方法中获取JavaScript端传递的事件和参数:

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;

WKScriptMessage 包含了传递的协议名称及参数, 主要从下面的属性中获取:

// 协议名称, 即上面的add方法传递的name
@property (nonatomic, readonly, copy) NSString *name;
// 传递的参数
@property (nonatomic, readonly, copy) id body;
// 发送消息的webView
@property (nullable, nonatomic, readonly, weak) WKWebView *webView;
//发送消息的帧
@property (nonatomic, readonly, copy) WKFrameInfo *frameInfo;
WKPreferences
// webView的偏好设置
//  minimum font size in points    default is 0;
@property (nonatomic) CGFloat minimumFontSize;
// 是否启用javaScript   default value is YES.
@property (nonatomic) BOOL javaScriptEnabled;
// 不通过用户交互,是否可以打开窗口
// default NO in iOS and YES in OS X.
@property (nonatomic) BOOL javaScriptCanOpenWindowsAutomatically;
.......
WKNavigationDelegate
// 当WevView的内容开始加载时触发
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
// 当页面加载内容过程中发生错误时触发
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
// 当WebView开始接收网页内容时触发
-(void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
// 当前页面加载完成后触发
-(void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
// 页面发生错误时触发
-(void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error;
// 当WebContent进程中止时触发
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView;
/* 决定是否允许或者取消一次页面加载请求
WKNavigationAction描述了触发本次请求的行为
decisionHandler block在app已经决定允许或取消页面请求时调用
这个block携带一个参数,是WKNavigationActionPolicy枚举类型
WKNavigationActionPolicy枚举包括WKNavigationActionPolicyCancel取消和WKNavigationActionPolicyAllow允许两个枚举值
你可以立即调用该block或者保存block并在以后的时间异步调用它
*/
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
/* 在已经收到response时决定是否允许或者取消页面的加载
WKNavigationResponse描述了response的信息
decisionHandler block在app已经决定允许或取消页面加载时调用
这个block携带一个参数,是WKNavigationResponsePolicy枚举类型
WKNavigationResponsePolicy枚举类型包括WKNavigationResponsePolicyCancel取消和WKNavigationResponsePolicyAllow允许两个枚举值
你可以立即调用该block或者保存block并在以后的时间异步调用它。
*/
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 当WebView需要响应网页的登录请求时触发
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;

WKUIDelegate
// 创建新的webview
// 可以指定配置对象、导航动作对象、window特性
- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
// webview关闭时回调
- (void)webViewDidClose:(WKWebView *)webView NS_AVAILABLE(10_11, 9_0);
// 调用JS的alert()方法
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;
// 调用JS的confirm()方法
- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler;
// 调用JS的prompt()方法
- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * __nullable result))completionHandler;
1859399-541a6e4c7204231b.png

WKWebView加载本地HTML

iOS中wkwebview加载本地html的要点
iOS之在webView中引入本地html,image,js,css文件的方法

扫描二维码关注公众号,回复: 5185943 查看本文章
方法一:WKWebView加载网页方法:loadRequest:

本地HTML路径获取方式有两种:pathForResourceURLForResource

NSString * localurl_1 = [[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"];
NSURLRequest *request = [NSURLRequest requestWithURL:[[NSURL alloc] initWithString:localurl_1]];
[_wkWebView loadRequest:request];
NSURL * localurl = [[NSBundle mainBundle] URLForResource:@"error" withExtension:@"html"];
NSURLRequest *request = [NSURLRequest requestWithURL:localurl];
[_wkWebView loadRequest:request];

WKWebView加载后发现 pathForResource 加载失败,可以看出:
1、pathForResource 的结果是纯路径
2、URLForResource 的结果是加file协议的路径

1859399-67196b0e10930084.png
本地HTML的路径

方法二:WKWebView加载网页方法:loadHTMLString: baseURL:

这种方式就是使用pathForResource来获取路径

NSString *urlStr = [[NSBundle mainBundle] pathForResource:@"index.html" ofType:nil];
NSString *localHtml = [NSString stringWithContentsOfFile:urlStr encoding:NSUTF8StringEncoding error:nil];
NSURL *fileURL = [NSURL fileURLWithPath:urlStr];
[_wkWebView loadHTMLString:localHtml baseURL:fileURL];
1859399-57ed82473de3da98.png

进度条显示(顺带获取title)

在适当的位置添加KVO观察者,离开时要移除

-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // KVO 观察WebView 进度条 和 title
    [_wkWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
    [_wkWebView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
}

-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    // 移除观察者
    [_wkWebView removeObserver:self forKeyPath:@"estimatedProgress"];
    [_wkWebView removeObserver:self forKeyPath:@"title"];
}

创建进度条

// Progress 进度条
    _progressView = [[UIProgressView alloc] init];
    _progressView.tintColor = [UIColor greenColor];
    _progressView.trackTintColor = [UIColor clearColor];
    [self.view addSubview:_progressView];

在KVO回调中修改页面

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"estimatedProgress"]) {
        if ([change[@"new"] floatValue] < [change[@"old"] floatValue]) {
            return;
        }
        if ([change[@"new"] floatValue] == 1.0) {
            [_progressView setProgress:1.0 animated:YES];
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                _progressView.hidden = YES;
                [_progressView setProgress:0 animated:NO];
            });
        } else {
            _progressView.hidden = NO;
            [_progressView setProgress:[change[@"new"] floatValue] animated:YES];
        }
    } else if ([keyPath isEqualToString:@"title"]){
        self.title = change[@"new"];
    }
}
1859399-b48998ffc3213afd.png

参考文档

简介
WKWebView详解
WKWebViewTips
[iOS]WKWebView的使用--API篇
WKWebView浅析
WKWebView代理方法解析

使用中的问题
iOS 11 WKWebView新特性
iOS WKWebView无法处理URL Scheme和App Store链接的问题解决
WKWebView使用过程中遇到的坑

iOS中UIWebView与WKWebView、JavaScript与OC交互、Cookie管理看我就够(上)
iOS中UIWebView与WKWebView、JavaScript与OC交互、Cookie管理看我就够(中)
iOS中UIWebView与WKWebView、JavaScript与OC交互、Cookie管理看我就够(下)

猜你喜欢

转载自blog.csdn.net/weixin_33835103/article/details/86878536