超詳細(xì) WKWebView 開發(fā)和使用經(jīng)驗
- WKWebView 幾個不常用的特性
- WKWebview 加載過程中的性能指標(biāo)圖解
- WKWebview 秒開的實踐及踩坑之路
今天分享的這篇文章全面的介紹了 WKWebView,作者根據(jù)開發(fā)和使用經(jīng)驗從屬性、方法、代理等方面詳細(xì)的做出了總結(jié)。
文章較長大家可以先通過目錄了解文章內(nèi)容。
- WKWebView 初始化
- WKWebViewConfiguration
- 代理方法
- WKNavigationDelegate
- WKUIDelegate
- 屬性和方法
- 歷史記錄管理
- WKBackForwardList
- WKBackForwardListItem
- 網(wǎng)頁加載
- WKWebViewConfiguration
- 進(jìn)程池 WKProcessPool
- 偏好設(shè)置 WKPreferences
- 用戶內(nèi)容控制 WKUserContentController
- 存儲 WKWebsiteDataStore
- 內(nèi)容渲染控制 suppressesIncrementalRendering
- 追加 User-Agent applicationNameForUserAgent
- 網(wǎng)頁多媒體播放
- 選擇粒度 WKSelectionGranularity
- 數(shù)據(jù)類型檢測 WKDataDetectorTypes
- 忽略網(wǎng)頁縮放設(shè)置 ignoresViewportScaleLimits
- 自定義攔截協(xié)議 iOS11 以上新支持
- 代理 WKNavigationDelegate
- decidePolicyForNavigationAction 首先決定網(wǎng)頁是否繼續(xù)訪問
- iOS13 新增 WKWebpagePreferences
- decidePolicyForNavigationResponse 是否允許響應(yīng)回調(diào)
- 當(dāng)主 Frame 開始加載頁面 didStartProvisionalNavigation
- 當(dāng)服務(wù)器發(fā)起重定向請求 didReceiveServerRedirectForProvisionalNavigation
- 當(dāng)容器在加載數(shù)據(jù)時發(fā)生了錯誤 didFailProvisionalNavigation
- 當(dāng)容器開始加載數(shù)據(jù)
- 當(dāng)網(wǎng)頁內(nèi)容開始在主 Frame 開始渲染
- 在提交主 Frame 導(dǎo)航期間發(fā)生了錯誤
- 當(dāng)接受 HTTPS 請求證書后執(zhí)行
- 當(dāng)容器內(nèi)容發(fā)生崩潰
- UI代理 WKUIDelegate
- 打開新的 WebView createWebViewWithConfiguration
- 關(guān)閉網(wǎng)頁 webViewDidClose
- 提示信息 runJavaScriptAlertPanelWithMessage
- 確認(rèn)信息提示框 runJavaScriptConfirmPanelWithMessage
- 輸入提示框 runJavaScriptTextInputPanelWithPrompt
- iOS 13 新增方法 contextMenu 的處理方法
- FAQ
WKWebView 初始化
WKWebViewConfiguration
WKWebView 如果需要個性化配置,則應(yīng)該使用以下方法進(jìn)行初始化。
- - (instancetype)initWithFrame:(CGRect)frame
- configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
示例代碼:
- WKWebViewConfiguration *conf = [WKWebViewConfiguration new];
- WKWebView *wk = [[WKWebView alloc] initWithFrame:CGRectZero configuration:conf];
代理方法
WKNavigationDelegate
WKWebView 網(wǎng)頁的導(dǎo)航代理,可以理解為網(wǎng)頁的生命周期事件循環(huán)。
WKUIDelegate
WKWebView 網(wǎng)頁的UI交互代理,對于 JS 中的 UI 類型操作需要實現(xiàn)對應(yīng)的方法,例如 window.alert、window.confirm 等操作。
屬性和方法
歷史記錄管理
WKWebView 系統(tǒng)默認(rèn)支持對網(wǎng)頁歷史記錄的管理,經(jīng)過實際測試 302 狀態(tài)碼的網(wǎng)頁請求不屬于歷史記錄,200 狀態(tài)碼的網(wǎng)頁請求屬于正常的歷史記錄。
WKBackForwardList
支持僅對歷史記錄列表和數(shù)據(jù)的獲取
WKBackForwardListItem
WKBackForwardListItem 為每一項歷史記錄的數(shù)據(jù)模型。
- /*! @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 的區(qū)別:
- initialURL 為本次網(wǎng)頁加載的初始請求
- URL 為本次網(wǎng)頁加載結(jié)束后的最終請求
- 兩者 URL 區(qū)別在于首次發(fā)起 302 跳轉(zhuǎn)的請求
- title 為本次網(wǎng)頁加載結(jié)束時的 標(biāo)簽
網(wǎng)頁加載
加載在線地址
正常情況下,一般用 loadRequest 方法加載即可。
- - (nullable WKNavigation *)loadRequest:(NSURLRequest *)request;
loadData 和 loadHTML 也能加載網(wǎng)絡(luò)地址,原理都是通過先獲取 NSData 后,利用該方法加載,但是要注意獲取 NSData 的過程是同步,如果網(wǎng)絡(luò)請求較慢,會造成主線程阻塞。
- NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
- // 直接加載H5數(shù)據(jù)
- // [wk loadHTMLString:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] baseURL:nil];
- [wk loadData:data MIMEType:@"text/html" characterEncodingName:@"UTF-8" baseURL:nil];
loadHTMLString 和 loadData 中的參數(shù)說明:
baseURL:會影響網(wǎng)頁加載過程中 css、js、圖片等資源文件的相對路徑,并不會影響絕對路徑。
MIMEType:為支持加載網(wǎng)頁的類型,有如下類型
文件拓展名 | 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:當(dāng)前返回信息的數(shù)據(jù)編碼格式: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));
- 其中 readAccessURL 參數(shù)不能為空,否則會造成應(yīng)用崩潰。
- readAccessURL 參數(shù):允許訪問的資源路徑,如果是在 Bundle 中加載本地 HTML,則需要設(shè)置該 HTML 所在的 Bundle 路徑,路徑設(shè)置好后,該目錄在 WKWebView 中被視為沙盒目錄,HTML 就可以訪問同級目錄下的資源文件。
Bundle 下示例:
HTML 主地址應(yīng)為:
YOUR_APP_PATH/WKBundle.bundle/sandbox/index.html
readAccessURL 應(yīng)為以下兩種:
- YOUR_APP_PATH/WKBundle.bundle/sandbox
- YOUR_APP_PATH/WKBundle.bundle/
readAccessURL 的參數(shù)為當(dāng)前 HTML 所在目錄允許訪問,該參數(shù)對 Bundle 目錄影響不大,對沙盒目錄影響較大。這個參數(shù)不可以設(shè)置為:YOUR_APP_PATH/WKBundle.bundle/sandbox/js,否則會造成訪問出錯。
其余訪問本地 HTML 的方法
- [wk loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:indexPath]]];
同樣,上文中的 loadData 和 loadHTML 也可以訪問本地 html,同樣也存在同步阻塞的問題。
沙盒目錄下資源加載
Docuemnt、Library 和 tmp 目錄
如果本地 HTML 放置在 Docuemnt ,Library 下的話, 則需要將目錄設(shè)置為所有靜態(tài)資源的最外層。例如目錄結(jié)構(gòu)為:
- ├─ html-demo
- | ├─ common
- | | ├─ index.css
- | | └─ index.js
- | ├─ pages
- | | ├─ relative-common
- | | | ├─ index.css
- | | | └─ index.js
- | | └─ index.html
如果將 html-demo 目錄放置在 Document、Library 目錄下
- 通過 [WKWebView loadFileURL:allowingReadAccessToURL:] 方法可以訪問當(dāng)前目錄下的相對資源,還需要設(shè)置指定訪問 allowingReadAccessToURL 下的資源,注意 allowingReadAccessToURL 需要設(shè)置 html 和 css 同時存在的最外層目錄,如上例中,我們將 allowingReadAccessToURL 所需參數(shù)設(shè)置為 html-demo 目錄的話,這樣既能訪問 common 目錄下的資源,也能訪問 relative-common 下的資源。
- 通過 [WKWebView loadRequest:] 方法訪問 index.html 的話,僅能訪問當(dāng)前頁面所在目錄下的相對路徑資源,無法訪問目錄外的資源,例如上例中,index.html 僅能訪問 relative-common 目錄下的資源,不能訪問 common 目錄下的資源。
- 通過 [WKWebView loadData:] 和 [WKWebView loadHTMLString:] 方法僅能加載當(dāng)前HTML內(nèi)容,無法加載資源文件,這種加載模式下,由于不需要訪問其他路徑下的資源,屬于單頁渲染和加載,所以效率高。
如果將 html-demo 目錄放置在 tmp 目錄下
- 通過 [WKWebView loadRequest:] 方法訪問 index.html 的話,既能訪問 common 下的資源,也能訪問 relative-common 下的資源。
- 其余規(guī)則同上。
WKWebView 屬性
webView 屬性
- title: 網(wǎng)頁的標(biāo)題,一般為 html 中的 中的內(nèi)容
- URL: 網(wǎng)頁的URL地址,為最終加載的地址
- loading: 網(wǎng)頁是否處于加載中,YES 加載中、 NO 加載完成
- estimatedProgress: 網(wǎng)頁加載進(jìn)度
- hasOnlySecureContent: 網(wǎng)頁上的所有資源是否已通過 https 加載
- serverTrust: 加載 HTTPS 請求服務(wù)端所信任的證書
以上屬性都可以采用 KVO 觀察屬性變化:
- // NSKeyValueObservingOptionNew 更改后的值
- // NSKeyValueObservingOptionOld 更改前的值
- // NSKeyValueObservingOptionInitial 觀察初始化的值(在注冊觀察服務(wù)時會調(diào)用一次觸發(fā)方法)
- // NSKeyValueObservingOptionPrior 分別在值修改前后觸發(fā)方法(即一次修改有兩次觸發(fā))
- [wk addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionInitial context:NULL];
注意:添加觀察者模式后,一定要在合適的時機(jī)將觀察者模式移除,否則在 iOS10 以下的設(shè)備會造成崩潰,原因是 WKWebView 在釋放的時候,扔被強(qiáng)持有觀察者。
- allowsBackForwardNavigationGestures: 允許手勢交互進(jìn)行頁面導(dǎo)航跳轉(zhuǎn)
- customUserAgent: 自定義 Web 頁面的 UserAgent,會覆蓋容器原有的 User-Agent 請求頭信息
- allowsLinkPreview: 允許 3Dtouch 預(yù)覽頁面,壓力屏存在的情況下
webView 方法
- canGoBack: 是否可以返回上一頁
- canGoForward: 是否可以前進(jìn)一頁
- goBack: 返回上一頁
- goForward: 前進(jìn)一頁
- eload: 根據(jù)當(dāng)前URL刷新頁面
- reloadFromOrigin: 根據(jù)最初 URL 刷新頁面
- stopLoading: 停止加載
- evaluateJavaScript: 執(zhí)行一段 js 代碼
- handlesURLScheme:(NSString *)urlScheme: 攔截自定義請求協(xié)議,不允許攔截 http,https,ws,wss,ftp
- takeSnapshotWithConfiguration: 截圖配置只能截取當(dāng)前一屏畫面
WKWebViewConfiguration
WebView 配置之 WKWebViewConfiguration
進(jìn)程池 WKProcessPool
WKProcessPool 用于提供給 WKWebView 獲取 Web 內(nèi)容的進(jìn)程池,里面包括 cookie 。當(dāng)一個 WebView初始化,一個新的 Web 內(nèi)容進(jìn)程會從一個特殊的進(jìn)程池中創(chuàng)建,或者一個已存在的進(jìn)程會被使用。
WKProcessPool 本身沒有任何方法和屬性,通過實現(xiàn)單例進(jìn)程池后,可以達(dá)到 WKWebView 間共享 cookie 的能力,注意:如果在賬戶退出登錄后,單例進(jìn)程需要釋放。
偏好設(shè)置 WKPreferences
WKWebView 的偏好設(shè)置,支持以下設(shè)置:
- minimumFontSize: 最小字體設(shè)置,默認(rèn)為 0, H5 中 css 的 “font-size” 的值如果小于該值,則會使用該值作為字體的最小尺寸。
- javaScriptEnabled: 是否啟用 js 腳本,默認(rèn)啟用,關(guān)閉則不會運算 js 腳本,加快渲染速度。
- javaScriptCanOpenWindowsAutomatically: 允許使用 js 自動打開 Window,默認(rèn)不允許,js 在調(diào)用 window.open 方法的時候,必須將改值設(shè)置為 YES,才能從 WKUIDelegate 的代理方法中獲取到。
用戶內(nèi)容控制 WKUserContentController
- 支持注入、移除 js 腳本
- 支持 Web 內(nèi)容規(guī)則
用戶腳本 WKUserScript
- WKUserScript *userScript = [[WKUserScript alloc] initWithSource:@"window.open('https://www.baidu.com')"
- injectionTime:(WKUserScriptInjectionTimeAtDocumentStart)
- forMainFrameOnly:YES];
屬性解釋:
- injectionTime: js 代碼的注入時機(jī),支持 WKUserScriptInjectionTimeAtDocumentStart ,WKUserScriptInjectionTimeAtDocumentEND,分別代表頁面剛渲染前執(zhí)行,和頁面渲染后執(zhí)行。
- forMainFrameOnly: 是否僅注入在主框架,還是包括所有的 iframe 全部注入。
添加用戶腳本 addUserScript
使用 addUserScript 方法來添加 js 腳本。
移除所有用戶腳本 removeAllUserScripts
如果注入時機(jī)為在網(wǎng)頁渲染前,那么網(wǎng)頁加載完畢后執(zhí)行移除腳本操作,則腳本的運算結(jié)果并不會受影響,但是在網(wǎng)頁加載完畢前移除腳本的后,腳本將不會執(zhí)行。
添加腳本消息通道 addScriptMessageHandler
用于 Native 和 js 通信,需要實現(xiàn) WKScriptMessageHandler 協(xié)議。
- 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)
- 可以在任何時機(jī)添加,可以添加多個
- 實現(xiàn) WKScriptMessageHandler 協(xié)議,并實現(xiàn) didReceiveScriptMessage 方法接受消息,通過 message.name 區(qū)分不通的協(xié)議
- - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
- {
- NSLog(@"%@", message.name);
- }
移除腳本消息通道 removeScriptMessageHandlerForName
根據(jù)腳本消息通道名稱移除對應(yīng)的腳本消息通道??梢栽谌魏螘r機(jī)移除,移除后對應(yīng)的js代碼也會移除。
iOS 11 以上支持內(nèi)容過濾規(guī)則配置
該配置需要結(jié)合內(nèi)容過濾器編譯一起使用,通過對 js 指定的規(guī)則編譯后得到一個 WKContentRuleList ,并且通過 userController 添加進(jìn) WebView 中。
存儲 WKWebsiteDataStore
以下情況中,WKWebView 在主動發(fā)送請求時不會攜帶 cookie。
- Ajax 請求不會帶上 Response 中 Set-Cookie 的值
- 302 跳轉(zhuǎn)不會帶上 Response 中 Set-Cookie 的值
可以使用 iOS11 的新 API 對 WKWebView 進(jìn)行 cookie 的設(shè)置,利用以下代碼對 Cookie 進(jìn)行持久化設(shè)置
- NSHTTPCookie *cookie = ....;
- [[WKWebsiteDataStore defaultDataStore].httpCookieStore setCookie:cookie ...];
- 該方法如果在 WKWebView 初始化之前設(shè)置,則請求可以立馬帶上 Cookie。
示例代碼:
- WKWebViewConfiguration *conf = [WKWebViewConfiguration new];
- // 在初始化方法之前,設(shè)置 cookie
- NSHTTPCookie *cookie = [NSHTTPCookie cookieWithPropertie:...];
- [[WKWebsiteDataStore defaultDataStore].httpCookieStore setCookie:cookie ...];
- WKWebView *wk = [[WKWebView alloc] initWithFrame:CGRectZero configuration:conf];
- [wk loadRequest:...];
- 該方法如果在 loadRequest 之前設(shè)置 cookie,則請求不會立馬帶上該 Cookie,會在下次請求中攜帶該 cookie。
- WKWebViewConfiguration *conf = [WKWebViewConfiguration new];
- WKWebView *wk = [[WKWebView alloc] initWithFrame:CGRectZero configuration:conf];
- // 在初始化方法之后,設(shè)置 cookie
- NSHTTPCookie *cookie = [NSHTTPCookie cookieWithPropertie:...];
- [[WKWebsiteDataStore defaultDataStore].httpCookieStore setCookie:cookie ...];
- [wk loadRequest:...];
內(nèi)容渲染控制 suppressesIncrementalRendering
是否等待 H5 內(nèi)容全部加載完成后才開始渲染畫面,默認(rèn)為 NO,如果設(shè)置為 YES,則 H5 在加載完成之前一直處于白屏狀態(tài)。
例如 H5 代碼:
- // 在測試H5頁面尾巴處加入如下代碼,可以查看區(qū)別。
- <script type="text/javascript">
- setTimeout(function(){
- for(var i = 1; i<10000; i++)
- {
- alert(i);
- }
- })
- </script>
追加 User-Agent applicationNameForUserAgent
不會覆蓋原來的請求頭重 User-Agent 的值屬性,在之后追加自定義的內(nèi)容。
網(wǎng)頁多媒體播放
allowsAirPlayForMediaPlayback
是否允許 AirPlay 投屏播放,默認(rèn)允許
mediaTypesRequiringUserActionForPlayback
哪些媒體文件需要強(qiáng)制用戶進(jìn)行手勢交互后才能播放。
- WKAudiovisualMediaTypeNone = 0, // 默認(rèn)無
- WKAudiovisualMediaTypeAudio = 1 << 0,// 音頻
- WKAudiovisualMediaTypeVideo = 1 << 1, //視頻
- WKAudiovisualMediaTypeAll = NSUIntegerMax// 所有
該屬性將影響 H5 中 video 標(biāo)簽的 autoplay 屬性
allowsInlineMediaPlayback
- 允許 H5 中的 Video 標(biāo)簽支持局部視頻播放,不會全屏視頻。
- 需要配合 Video 標(biāo)簽的 playinline="true" 屬性,就可以實現(xiàn)局部播放。
allowsPictureInPictureMediaPlayback
A Boolean value indicating whether HTML5 videos may play picture-in-picture.
允許 H5 中 Video 標(biāo)簽支持畫中畫模式,默認(rèn) YES
可以使用 H5 中的 JS 代碼實現(xiàn)畫中畫,video.requestPictureInPicture(),iPhone 不支持,iPad 支持。
選擇粒度 WKSelectionGranularity
用戶可以交互選擇web視圖中的內(nèi)容的粒度級別.默認(rèn)是 WKSelectionGranularityDynamic 暫時不知道用于什么場景之下。
數(shù)據(jù)類型檢測 WKDataDetectorTypes
支持識別 HTML 的中字符信息:
- UIDataDetectorTypePhoneNumber // 手機(jī)號
- UIDataDetectorTypeLink // 網(wǎng)頁地址
- UIDataDetectorTypeAddress // 郵件地址
- UIDataDetectorTypeCalendarEvent // 格式化為日歷事件的信息
- UIDataDetectorTypeShipmentTrackingNumber // 快遞包裹信息
- UIDataDetectorTypeFlightNumber // 航班號信息
- UIDataDetectorTypeLookupSuggestion // 用戶可能要查找的信息
- UIDataDetectorTypeNone // 默認(rèn),不檢測
- UIDataDetectorTypeAll // 識別全部信息
默認(rèn)為 UIDataDetectorTypeNone,開啟檢測會影響網(wǎng)頁渲染速度。
忽略網(wǎng)頁縮放設(shè)置 ignoresViewportScaleLimits
ignoresViewportScaleLimits 是否忽略頁面縮放限制,默認(rèn)為 NO。
- 如果配置為 YES,當(dāng)前 Web 頁面可以通過放大手勢進(jìn)行縮放。
和 H5 中的參數(shù)存在關(guān)聯(lián):
- <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=0.5,user-scalable=yes" />
- minimum-scale=1
- maximum-scale=1
- user-scalable=yes
名稱 | ||||
---|---|---|---|---|
ignoresViewportScaleLimits | NO | NO | YES | YES |
user-scalable | YES | NO | YES | NO |
結(jié)論 | 按照指定尺寸進(jìn)行縮放 | 無法進(jìn)行縮放 | 任意放大 | 任意放大 |
自定義攔截協(xié)議 iOS11 以上新支持
- - (void)setURLSchemeHandler:(nullable id <WKURLSchemeHandler>)urlSchemeHandler
- forURLScheme:(NSString *)urlScheme API_AVAILABLE(macos(10.13), ios(11.0));
- - (nullable id <WKURLSchemeHandler>)urlSchemeHandlerForURLScheme:(NSString *)urlScheme API_AVAILABLE(macos(10.13), ios(11.0));
我們可以通過上述方法對 WKWebView 進(jìn)行自定義協(xié)議攔截,無法攔截 http、https、ws、wss、ftp 協(xié)議。
示例代碼:
- [conf setURLSchemeHandler:[ViewSchemaHandler new] forURLScheme:@"h5"];
在 ViewSchemaHandler 實現(xiàn)協(xié)議中的內(nèi)容
- - (void)webView:(WKWebView *)webView startURLSchemeTask:(id<WKURLSchemeTask>)urlSchemeTask
- {
- // 在這里可以對同一資源進(jìn)行本地緩存,無需要再次訪問。
- 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<WKURLSchemeTask>)urlSchemeTask
- {
- // 當(dāng)前urlSchemeTask由于某些原因提前結(jié)束了(會收到stopURLSchemeTask回調(diào))
- }
注意:
- 在 H5 前端所有想要攔截的 js,css 或者其他網(wǎng)絡(luò)請求資源,需要將路徑寫成自適應(yīng)協(xié)議路徑,例如如下寫法即可:
- <script type="text/javascript" src="//192.168.1.150:3206/7.3.7/js/libs/jquery.min.js" ></script>
- 在 H5 前端所有想要攔截的 Ajax 請求,需要將請求更改為相對或者絕對路徑,即可實現(xiàn)攔截
- $.ajax({
- url:"/abcd"
- });
可以利用上述特性實現(xiàn)應(yīng)用秒開。
代理 WKNavigationDelegate
decidePolicyForNavigationAction 首先決定網(wǎng)頁是否繼續(xù)訪問
可以通過 decidePolicyForNavigationAction 中的 decisionHandler 回調(diào)方法進(jìn)行回調(diào)。
WKNavigationActionPolicyCancel 取消訪問 WKNavigationActionPolicyAllow 允許繼續(xù)訪問,如果不實現(xiàn)該代理方法,則默認(rèn)允許訪問
示例代碼:
- - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
- {
- // decisionHandler(WKNavigationActionPolicyCancel);
- decisionHandler(WKNavigationActionPolicyAllow);
- }
iOS13 新增 WKWebpagePreferences
支持偏好設(shè)置,暫不理解。
decidePolicyForNavigationResponse 是否允許響應(yīng)回調(diào)
是否允許響應(yīng)回調(diào),操作同 decidePolicyForNavigationAction 一致。
當(dāng)主 Frame 開始加載頁面 didStartProvisionalNavigation
didStartProvisionalNavigation 發(fā)起首次請求會執(zhí)行這個方法,多次 302 重定向請求,該方法只會執(zhí)行一次,發(fā)生 多次 302 跳轉(zhuǎn)的時候,每次都會先執(zhí)行 decidePolicyForNavigationAction ,如果這時候用戶選擇 cancel 操作,則 didReceiveServerRedirectForProvisionalNavigation 方法不會執(zhí)行。
當(dāng)服務(wù)器發(fā)起重定向請求 didReceiveServerRedirectForProvisionalNavigation
didReceiveServerRedirectForProvisionalNavigation,發(fā)生 302 重定向會走該方法
當(dāng)容器在加載數(shù)據(jù)時發(fā)生了錯誤 didFailProvisionalNavigation
正常加載地址或者使用 js 中的 location.href 加載錯誤的地址發(fā)生失敗會走該回調(diào)。
- [WKWebView loadRequest:] // 發(fā)生失敗會走該回調(diào)
- // js代碼
- location.href="http://abcd" // 發(fā)生失敗會走該回調(diào)
當(dāng)容器開始加載數(shù)據(jù)
didCommitNavigation,網(wǎng)絡(luò)請求加載完成后執(zhí)行。
當(dāng)網(wǎng)頁內(nèi)容開始在主 Frame 開始渲染
didFinishNavigation 完成 js,css,html 渲染后執(zhí)行。
在提交主 Frame 導(dǎo)航期間發(fā)生了錯誤
didFailNavigation,例如:
- window.open("http://abcd") // 發(fā)生失敗后會走該回調(diào)
當(dāng)接受 HTTPS 請求證書后執(zhí)行
didReceiveAuthenticationChallenge,可以通過 completionHandler 來選擇對證書的操作,例如忽略證書。
- /*
- NSURLSessionAuthChallengeUseCredential = 0, 使用證書
- NSURLSessionAuthChallengePerformDefaultHandling = 1, 忽略證書(默認(rèn)的處理方式)
- NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, 忽略書證, 并取消這次請求
- NSURLSessionAuthChallengeRejectProtectionSpace = 3, 拒絕當(dāng)前這一次, 下一次再詢問
- */
- // NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
- NSURLCredential *card = [[NSURLCredential alloc]initWithTrust:challenge.protectionSpace.serverTrust];
- completionHandler(NSURLSessionAuthChallengeUseCredential , card);
當(dāng)容器內(nèi)容發(fā)生崩潰
webViewWebContentProcessDidTerminate,webView 內(nèi)容發(fā)生崩潰而終止,將會執(zhí)行該回調(diào)方法。
UI代理 WKUIDelegate
UI 代理方法,是 H5 部分 UI 操作和原生交互的代理方法,其中包括如下:
打開新的 WebView createWebViewWithConfiguration
H5 中需要打開新窗口的操作,都會被這個方法攔截,例如
- <a href="https://www.baidu.com" target="_blank" >打開新窗口</a>
- window.open("https://www.baidu.com");
關(guān)閉網(wǎng)頁 webViewDidClose
當(dāng) H5 執(zhí)行 window.close() 方法,則會執(zhí)行這個代理方法。
提示信息 runJavaScriptAlertPanelWithMessage
當(dāng) H5 執(zhí)行 window.alert(...args) 方法,則會執(zhí)行這個代理方法,需要注意:
completionHandler 這個 block 方法必須執(zhí)行,否則會發(fā)生崩潰,彈出窗口如果使用 UIAlertController 作為對接,則要考慮控制器是否存在,是否有并發(fā)的彈出窗操作,因為這些會導(dǎo)致 UIAlertController彈不出來,最終可能在邏輯上造成 completionHandler 無法執(zhí)行導(dǎo)致崩潰,最好建議彈窗應(yīng)該使用 UIView 設(shè)計。
確認(rèn)信息提示框 runJavaScriptConfirmPanelWithMessage
當(dāng) H5 執(zhí)行 window.confirm(...args),則會執(zhí)行這個代理方法,注意事項同上。
輸入提示框 runJavaScriptTextInputPanelWithPrompt
當(dāng)H5執(zhí)行 window.prompt(...args),則會執(zhí)行這個代理方法,注意事項同上。
iOS 13 新增方法 contextMenu 的處理方法
contextMenu 的相關(guān)處理方法,暫時不理解在手機(jī)端有何用處。
FAQ
- WKWebView 中 H5 css 動畫失效的問題?
目前測試下來
- [UIView snapshotViewAfterScreenUpdates:YES];
- [UIView drawViewHierarchyInRect:CGRect afterScreenUpdates:YES];
這兩種方法在進(jìn)行系統(tǒng) UIView 的截圖操作時候并且將參數(shù) afterScreenUpdates 設(shè)置為 YES 的情況下,最后 頻繁調(diào)用后會導(dǎo)致 H5 中 css 動畫失效,原因不明。