[[415926]] 本文转载自微信公众号「网罗开发」,作者兜里有糖同志。转载本文请联系网罗开发公众号。 根据需求需要将老项目中的 WebView 替换成 WKWebView,期间查阅了不少文档和资料,之前也发布了几篇 WKWebView 相关的优秀文章。

创新互联是专业的海口网站建设公司,海口接单;提供成都网站建设、成都网站制作,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行海口网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
今天分享的这篇文章全面的介绍了 WKWebView,作者根据开发和使用经验从属性、方法、代理等方面详细的做出了总结。
文章较长大家可以先通过目录了解文章内容。
WKWebView 如果需要个性化配置,则应该使用以下方法进行初始化。
- - (instancetype)initWithFrame:(CGRect)frame
 - configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
 
示例代码:
- WKWebViewConfiguration *conf = [WKWebViewConfiguration new];
 - WKWebView *wk = [[WKWebView alloc] initWithFrame:CGRectZero configuration:conf];
 
WKWebView 网页的导航代理,可以理解为网页的生命周期事件循环。
WKWebView 网页的UI交互代理,对于 JS 中的 UI 类型操作需要实现对应的方法,例如 window.alert、window.confirm 等操作。
WKWebView 系统默认支持对网页历史记录的管理,经过实际测试 302 状态码的网页请求不属于历史记录,200 状态码的网页请求属于正常的历史记录。
支持仅对历史记录列表和数据的获取
WKBackForwardListItem 为每一项历史记录的数据模型。
- /*! @abstract The URL of the webpage represented by this item.
 - */
 - @property (readonly, copy) NSURL *URL;
 - /*! @abstract The title of the webpage represented by this item.
 - */
 - @property (nullable, readonly, copy) NSString *title;
 - /*! @abstract The URL of the initial request that created this item.
 - */
 - @property (readonly, copy) NSURL *initialURL;
 
其中 initialURL 和 URL 的区别:
加载在线地址
正常情况下,一般用 loadRequest 方法加载即可。
- - (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
 
loadData 和 loadHTML 也能加载网络地址,原理都是通过先获取 NSData 后,利用该方法加载,但是要注意获取 NSData 的过程是同步,如果网络请求较慢,会造成主线程阻塞。
- NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
 - // 直接加载H5数据
 - // [wk loadHTMLString:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] baseURL:nil];
 - [wk loadData:data MIMEType:@"text/html" characterEncodingName:@"UTF-8" baseURL:nil];
 
loadHTMLString 和 loadData 中的参数说明:
baseURL:会影响网页加载过程中 css、js、图片等资源文件的相对路径,并不会影响绝对路径。
MIMEType:为支持加载网页的类型,有如下类型
| 文件拓展名 | MIMEType | 
|---|---|
| png | image/png | 
| bmp/dib | image/bmp | 
| jpg/jpeg/jpg | image/ipeg | 
| gif | image/gif | 
| mp3 | audio/mpeg | 
| mp4/mpg4/m4v/mp4v | video/mp4 | 
| js | application/javascript | 
| application/pdf | |
| text/txt | text/plain | 
| json | application/json | 
| xml | text/xml | 
characterEncodingName:当前返回信息的数据编码格式:UTF-8、UTF-16、UTF-32、GBK、GB2312等,一般使用 UTF-8。
加载本地地址
Bundle下资源加载
iOS9.0 以上可以使用以下方法加载
- - (nullable WKNavigation *)loadFileURL:(NSURL *)URL
 - allowingReadAccessToURL:(NSURL *)readAccessURL API_AVAILABLE(macos(10.11), ios(9.0));
 
HTML 主地址应为:
YOUR_APP_PATH/WKBundle.bundle/sandbox/index.html
readAccessURL 应为以下两种:
readAccessURL 的参数为当前 HTML 所在目录允许访问,该参数对 Bundle 目录影响不大,对沙盒目录影响较大。这个参数不可以设置为:YOUR_APP_PATH/WKBundle.bundle/sandbox/js,否则会造成访问出错。
其余访问本地 HTML 的方法
- [wk loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:indexPath]]];
 
同样,上文中的 loadData 和 loadHTML 也可以访问本地 html,同样也存在同步阻塞的问题。
沙盒目录下资源加载
Docuemnt、Library 和 tmp 目录
如果本地 HTML 放置在 Docuemnt ,Library 下的话, 则需要将目录设置为所有静态资源的最外层。例如目录结构为:
- ├─ html-demo
 - | ├─ common
 - | | ├─ index.css
 - | | └─ index.js
 - | ├─ pages
 - | | ├─ relative-common
 - | | | ├─ index.css
 - | | | └─ index.js
 - | | └─ index.html
 
如果将 html-demo 目录放置在 Document、Library 目录下
如果将 html-demo 目录放置在 tmp 目录下
webView 属性
以上属性都可以采用 KVO 观察属性变化:
- // NSKeyValueObservingOptionNew 更改后的值
 - // NSKeyValueObservingOptionOld 更改前的值
 - // NSKeyValueObservingOptionInitial 观察初始化的值(在注册观察服务时会调用一次触发方法)
 - // NSKeyValueObservingOptionPrior 分别在值修改前后触发方法(即一次修改有两次触发)
 - [wk addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionInitial context:NULL];
 
注意:添加观察者模式后,一定要在合适的时机将观察者模式移除,否则在 iOS10 以下的设备会造成崩溃,原因是 WKWebView 在释放的时候,扔被强持有观察者。
webView 方法
WebView 配置之 WKWebViewConfiguration
WKProcessPool 用于提供给 WKWebView 获取 Web 内容的进程池,里面包括 cookie 。当一个 WebView初始化,一个新的 Web 内容进程会从一个特殊的进程池中创建,或者一个已存在的进程会被使用。
WKProcessPool 本身没有任何方法和属性,通过实现单例进程池后,可以达到 WKWebView 间共享 cookie 的能力,注意:如果在账户退出登录后,单例进程需要释放。
WKWebView 的偏好设置,支持以下设置:
用户内容控制 WKUserContentController
用户脚本 WKUserScript
- WKUserScript *userScript = [[WKUserScript alloc] initWithSource:@"window.open('https://www.baidu.com')"
 - injectionTime:(WKUserScriptInjectionTimeAtDocumentStart)
 - forMainFrameOnly:YES];
 
属性解释:
添加用户脚本 addUserScript
使用 addUserScript 方法来添加 js 脚本。
移除所有用户脚本 removeAllUserScripts
如果注入时机为在网页渲染前,那么网页加载完毕后执行移除脚本操作,则脚本的运算结果并不会受影响,但是在网页加载完毕前移除脚本的后,脚本将不会执行。
添加脚本消息通道 addScriptMessageHandler
用于 Native 和 js 通信,需要实现 WKScriptMessageHandler 协议。
- WKUserContentController *userController = [[WKUserContentController alloc] init];
 - [userController addScriptMessageHandler:self name:@"JSBridge"];
 - [userController addScriptMessageHandler:self name:@"HWH5"];
 - conf.userContentController = userController;
 - JS代码
 - window.webkit.messageHandlers.JSBridge.postMessage(...args)
 - window.webkit.messageHandlers.HWH5.postMessage(...args)
 
- - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
 - {
 - NSLog(@"%@", message.name);
 - }
 
移除脚本消息通道 removeScriptMessageHandlerForName
根据脚本消息通道名称移除对应的脚本消息通道。可以在任何时机移除,移除后对应的js代码也会移除。
iOS 11 以上支持内容过滤规则配置
该配置需要结合内容过滤器编译一起使用,通过对 js 指定的规则编译后得到一个 WKContentRuleList ,并且通过 userController 添加进 WebView 中。
以下情况中,WKWebView 在主动发送请求时不会携带 cookie。
可以使用 iOS11 的新 API 对 WKWebView 进行 cookie 的设置,利用以下代码对 Cookie 进行持久化设置
- NSHTTPCookie *cookie = ....;
 - [[WKWebsiteDataStore defaultDataStore].httpCookieStore setCookie:cookie ...];
 
示例代码:
- WKWebViewConfiguration *conf = [WKWebViewConfiguration new];
 - // 在初始化方法之前,设置 cookie
 - NSHTTPCookie *cookie = [NSHTTPCookie cookieWithPropertie:...];
 - [[WKWebsiteDataStore defaultDataStore].httpCookieStore setCookie:cookie ...];
 - WKWebView *wk = [[WKWebView alloc] initWithFrame:CGRectZero configuration:conf];
 - [wk loadRequest:...];
 
- WKWebViewConfiguration *conf = [WKWebViewConfiguration new];
 - WKWebView *wk = [[WKWebView alloc] initWithFrame:CGRectZero configuration:conf];
 - // 在初始化方法之后,设置 cookie
 - NSHTTPCookie *cookie = [NSHTTPCookie cookieWithPropertie:...];
 - [[WKWebsiteDataStore defaultDataStore].httpCookieStore setCookie:cookie ...];
 - [wk loadRequest:...];
 
内容渲染控制 suppressesIncrementalRendering
是否等待 H5 内容全部加载完成后才开始渲染画面,默认为 NO,如果设置为 YES,则 H5 在加载完成之前一直处于白屏状态。
例如 H5 代码:
- // 在测试H5页面尾巴处加入如下代码,可以查看区别。
 
追加 User-Agent applicationNameForUserAgent
不会覆盖原来的请求头重 User-Agent 的值属性,在之后追加自定义的内容。
allowsAirPlayForMediaPlayback
是否允许 AirPlay 投屏播放,默认允许
mediaTypesRequiringUserActionForPlayback
哪些媒体文件需要强制用户进行手势交互后才能播放。
该属性将影响 H5 中 video 标签的 autoplay 属性
allowsInlineMediaPlayback
allowsPictureInPictureMediaPlayback
A Boolean value indicating whether HTML5 videos may play picture-in-picture.
允许 H5 中 Video 标签支持画中画模式,默认 YES
可以使用 H5 中的 JS 代码实现画中画,video.requestPictureInPicture(),iPhone 不支持,iPad 支持。
用户可以交互选择web视图中的内容的粒度级别.默认是 WKSelectionGranularityDynamic 暂时不知道用于什么场景之下。
支持识别 HTML 的中字符信息:
- UIDataDetectorTypePhoneNumber // 手机号
 - UIDataDetectorTypeLink // 网页地址
 - UIDataDetectorTypeAddress // 邮件地址
 - UIDataDetectorTypeCalendarEvent // 格式化为日历事件的信息
 - UIDataDetectorTypeShipmentTrackingNumber // 快递包裹信息
 - UIDataDetectorTypeFlightNumber // 航班号信息
 - UIDataDetectorTypeLookupSuggestion // 用户可能要查找的信息
 - UIDataDetectorTypeNone // 默认,不检测
 - UIDataDetectorTypeAll // 识别全部信息
 
默认为 UIDataDetectorTypeNone,开启检测会影响网页渲染速度。
ignoresViewportScaleLimits 是否忽略页面缩放限制,默认为 NO。
和 H5 中的参数存在关联:
| 名称 | ||||
|---|---|---|---|---|
| ignoresViewportScaleLimits | NO | NO | YES | YES | 
| user-scalable | YES | NO | YES | NO | 
| 结论 | 按照指定尺寸进行缩放 | 无法进行缩放 | 任意放大 | 任意放大 | 
- - (void)setURLSchemeHandler:(nullable id
 )urlSchemeHandler - forURLScheme:(NSString *)urlScheme API_AVAILABLE(macos(10.13), ios(11.0));
 - - (nullable id
 )urlSchemeHandlerForURLScheme:(NSString *)urlScheme API_AVAILABLE(macos(10.13), ios(11.0)); 
我们可以通过上述方法对 WKWebView 进行自定义协议拦截,无法拦截 http、https、ws、wss、ftp 协议。
示例代码:
- [conf setURLSchemeHandler:[ViewSchemaHandler new] forURLScheme:@"h5"];
 
在 ViewSchemaHandler 实现协议中的内容
- - (void)webView:(WKWebView *)webView startURLSchemeTask:(id
 )urlSchemeTask - {
 - // 在这里可以对同一资源进行本地缓存,无需要再次访问。
 - NSMutableURLRequest *request = urlSchemeTask.request.mutableCopy;
 - request.URL = [NSURL URLWithString:[request.URL.absoluteString stringByReplacingOccurrencesOfString:@"h5://" withString:@"http://"]];
 - NSLog(@"%@", request.URL.absoluteURL);
 - NSURLSession* session = [NSURLSession sharedSession];
 - NSURLSessionTask* task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
 - [urlSchemeTask didReceiveResponse:response];
 - [urlSchemeTask didReceiveData:data];
 - [urlSchemeTask didFinish];
 - }];
 - [task resume];
 - }
 - - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id
 )urlSchemeTask - {
 - // 当前urlSchemeTask由于某些原因提前结束了(会收到stopURLSchemeTask回调)
 - }
 
注意:
- $.ajax({
 - url:"/abcd"
 - });
 
可以利用上述特性实现应用秒开。
decidePolicyForNavigationAction 首先决定网页是否继续访问
可以通过 decidePolicyForNavigationAction 中的 decisionHandler 回调方法进行回调。
WKNavigationActionPolicyCancel 取消访问 WKNavigationActionPolicyAllow 允许继续访问,如果不实现该代理方法,则默认允许访问
示例代码:
- - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
 - {
 - // decisionHandler(WKNavigationActionPolicyCancel);
 - decisionHandler(WKNavigationActionPolicyAllow);
 - }
 
iOS13 新增 WKWebpagePreferences
支持偏好设置,暂不理解。
decidePolicyForNavigationResponse 是否允许响应回调
是否允许响应回调,操作同 decidePolicyForNavigationAction 一致。
当主 Frame 开始加载页面 didStartProvisionalNavigation
didStartProvisionalNavigation 发起首次请求会执行这个方法,多次 302 重定向请求,该方法只会执行一次,发生 多次 302 跳转的时候,每次都会先执行 decidePolicyForNavigationAction ,如果这时候用户选择 cancel 操作,则 didReceiveServerRedirectForProvisionalNavigation 方法不会执行。
当服务器发起重定向请求 didReceiveServerRedirectForProvisionalNavigation
didReceiveServerRedirectForProvisionalNavigation,发生 302 重定向会走该方法
当容器在加载数据时发生了错误 didFailProvisionalNavigation
正常加载地址或者使用 js 中的 location.href 加载错误的地址发生失败会走该回调。
- [WKWebView loadRequest:] // 发生失败会走该回调
 - // js代码
 - location.href="http://abcd" // 发生失败会走该回调
 
当容器开始加载数据
didCommitNavigation,网络请求加载完成后执行。
当网页内容开始在主 Frame 开始渲染
didFinishNavigation 完成 js,css,html 渲染后执行。
在提交主 Frame 导航期间发生了错误
didFailNavigation,例如:
- window.open("http://abcd") // 发生失败后会走该回调
 
当接受 HTTPS 请求证书后执行
didReceiveAuthenticationChallenge,可以通过 completionHandler 来选择对证书的操作,例如忽略证书。
- /*
 - NSURLSessionAuthChallengeUseCredential = 0, 使用证书
 - NSURLSessionAuthChallengePerformDefaultHandling = 1, 忽略证书(默认的处理方式)
 - NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, 忽略书证, 并取消这次请求
 - NSURLSessionAuthChallengeRejectProtectionSpace = 3, 拒绝当前这一次, 下一次再询问
 - */
 - // NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
 - NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
 - completionHandler(NSURLSessionAuthChallengeUseCredential , card);
 
当容器内容发生崩溃
webViewWebContentProcessDidTerminate,webView 内容发生崩溃而终止,将会执行该回调方法。
UI 代理方法,是 H5 部分 UI 操作和原生交互的代理方法,其中包括如下:
打开新的 WebView createWebViewWithConfiguration
H5 中需要打开新窗口的操作,都会被这个方法拦截,例如
- 打开新窗口
 - window.open("https://www.baidu.com");
 
关闭网页 webViewDidClose
当 H5 执行 window.close() 方法,则会执行这个代理方法。
提示信息 runJavaScriptAlertPanelWithMessage
当 H5 执行 window.alert(...args) 方法,则会执行这个代理方法,需要注意:
completionHandler 这个 block 方法必须执行,否则会发生崩溃,弹出窗口如果使用 UIAlertController 作为对接,则要考虑控制器是否存在,是否有并发的弹出窗操作,因为这些会导致 UIAlertController弹不出来,最终可能在逻辑上造成 completionHandler 无法执行导致崩溃,最好建议弹窗应该使用 UIView 设计。
确认信息提示框 runJavaScriptConfirmPanelWithMessage
当 H5 执行 window.confirm(...args),则会执行这个代理方法,注意事项同上。
输入提示框 runJavaScriptTextInputPanelWithPrompt
当H5执行 window.prompt(...args),则会执行这个代理方法,注意事项同上。
iOS 13 新增方法 contextMenu 的处理方法
contextMenu 的相关处理方法,暂时不理解在手机端有何用处。
FAQ
目前测试下来
这两种方法在进行系统 UIView 的截图操作时候并且将参数 afterScreenUpdates 设置为 YES 的情况下,最后 频繁调用后会导致 H5 中 css 动画失效,原因不明。
                名称栏目:超详细WKWebView开发和使用经验
                
                转载注明:http://www.csdahua.cn/qtweb/news19/501619.html
            
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网