生活随笔
收集整理的這篇文章主要介紹了
iOS之深入解析WKWebView的坑点收录和优化处理
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、Cookie 處理
① Cookie 說明
WKWebView 在設置 Cookie 的時候,經常做的是在請求的請求頭里添加 Cookie,但這只是把 Cookie 發送給了服務端,本地并沒有保存 Cookie,Cookie 最終要寫到 WebView 的一個 Cookie 文件目錄里面,后續 WebView 里面自己的發起的請求或者跳轉才能在發起請求的時候,在對應的域名下面取到 Cookie 傳出去。 Webview 加載 H5 頁面,實際上是把頁面相關的 .html、js、css 文件下載到本地,然后再加載,這時頁面去獲取 Cookie 的時候,是去本地 WebView 里的 Cookie 文件目錄里查找,如果沒有設置的話肯定就獲取不到,所以在設置 Cookie 的時候,服務端和客戶端都要設置。
② 服務端 Cookie 設置
在使用 UIWebView 的時候,是通過 NSHTTPCookieStorage 來管理 Cookie 的,如下,給 baidu.tech 這個域名添加一個名為 user 的 Cookie:
var props
= Dictionary
< HTTPCookiePropertyKey
, Any
> ( ) props
[ HTTPCookiePropertyKey
. name
] = "user" props
[ HTTPCookiePropertyKey
. value
] = "admin" props
[ HTTPCookiePropertyKey
. path
] = "/" props
[ HTTPCookiePropertyKey
. domain
] = "baidu.tech" props
[ HTTPCookiePropertyKey
. version
] = "0" props
[ HTTPCookiePropertyKey
. originURL
] = "baidu.tech" if let cookie
= HTTPCookie ( properties
: props
) { HTTPCookieStorage
. shared
. setCookie ( cookie
) }
WKWebView Cookie 問題在于 WKWebView 發起的請求不會自動帶上存儲于 NSHTTPCookieStorage 容器中的 Cookie。解決辦法也很簡單,就是在 WKWebView 發起請求之前,先從 NSHTTPCookieStorage 讀取 Cookie,然后手動往 URLRequest 的請求頭里添加一下 Cookie:
func
getCookie ( ) -> String
{ var cookieString
= "" if let cookies
= HTTPCookieStorage
. shared
. cookies
{ for cookie
in cookies
{ if cookie
. domain
== cookieDomain
{ let str
= "\(cookie.name)=\(cookie.value)" cookieString
. append ( "\(str);" ) } } return cookieString
} var request
= URLRequest ( url
: URL ( string
: "https://baidu.tech" ) ) request
. addValue ( getCookie ( ) , forHTTPHeaderField
: "Cookie" )
當服務器頁面發生重定向的時候,此時第一次在 RequestHeader 中寫入的 Cookie 會丟失,還需要對重定向的請求重新做添加 Cookie 的處理。
② 客戶端 Cookie 設置
當頁面加載的時候,后端無論是啥語言,都能從請求頭里看到 Cookie 了,但是后端渲染返回頁面后,在客戶端的 WebView 里運行的時候,JS 在執行的時候調用 document.cookie API 是讀取不到 Cookie 的,所以還得針對客戶端 Cookie 進行處理:
var cookieString
= "" if let cookies
= HTTPCookieStorage
. shared
. cookies
{ for cookie
in cookies
{ if cookie
. domain
== "baidu.tech" { let str
= "\(cookie.name)=\(cookie.value)" cookieString
. append ( "document.cookie='\(str);path=/;domain=baidu.tech';" ) } } } let cookieScript
= WKUserScript ( source
: cookieString
, injectionTime
: . atDocumentStart
, forMainFrameOnly
: false
) let userContentController
= WKUserContentController ( ) userContentController
. addUserScript ( cookieScript
) let webViewConfig
= WKWebViewConfiguration ( ) webViewConfig
. userContentController
= userContentControllerlet webV
= WKWebView ( frame
: CGRect
. zero
, configuration
: webViewConfig
)
客戶端 Cookie 注入實際上就是創建一個 JS 腳本,讓 WebView 去執行,推薦在 .atDocumentStart 這個時機進行預置靜態 JS 的注入,這樣 WebView 在加載后端返回的靜態頁面的時候,就可以拿到保存著客戶端的 Cookie 了。
二、URL 攔截
① Web 頁面重定向問題
在 WKWebView 中,每一次頁面跳轉之前,都會調用下面的回調函數:
func
webView ( _ webView
: WKWebView
, decidePolicyFor navigationAction
: WKNavigationAction
, decisionHandler
: @ escaping ( WKNavigationActionPolicy
) -> Void
)
重定向問題有兩種: 服務器頁面重定向,需要對新發起的請求重新設置 Cookie; 本地頁面重定向,只要客戶端設置了 Cookie,那么就不需要再處理。 因此,如果是服務器頁面重定向,那么判斷此時 Request 是否有需要的 Cookie,沒有就 Cancel 掉,修改 Request 重新發起。
func
webView ( _ webView
: WKWebView
, decidePolicyFor navigationAction
: WKNavigationAction
, decisionHandler
: @ escaping ( WKNavigationActionPolicy
) -> Void
) { var shouldCancelLoadURL
= false
if let cookie
= navigationAction
. request
. value ( forHTTPHeaderField
: "Cookie" ) { if cookie
. contains ( "user" ) { shouldCancelLoadURL
= false
} else { var request
= URLRequest ( url
: URL ( string
: ( navigationAction
. request
. url
? . absoluteString
) ! ) ! ) request
. addValue ( getCookie ( ) , forHTTPHeaderField
: "Cookie" ) webView
. load ( request
) shouldCancelLoadURL
= true
} } else { var request
= URLRequest ( url
: URL ( string
: ( navigationAction
. request
. url
? . absoluteString
) ! ) ! ) request
. addValue ( getCookie ( ) , forHTTPHeaderField
: "Cookie" ) webView
. load ( request
) shouldCancelLoadURL
= true
} if shouldCancelLoadURL
{ decisionHandler ( WKNavigationActionPolicy
. cancel
) } else { decisionHandler ( WKNavigationActionPolicy
. allow
) } }
② 跨域問題
針對跨域的問題,解決辦法和上面的方法類似,僅僅是判斷條件不同:
func
webView ( _ webView
: WKWebView
, decidePolicyFor navigationAction
: WKNavigationAction
, decisionHandler
: @ escaping ( WKNavigationActionPolicy
) -> Void
) { var shouldCancelLoadURL
= false
if let url
= navigationAction
. request
. url
? . absoluteString
{ if url
. contains ( "baidu.tech" ) { shouldCancelLoadURL
= false
} else { shouldCancelLoadURL
= true
} } else { shouldCancelLoadURL
= true
} if shouldCancelLoadURL
{ decisionHandler ( WKNavigationActionPolicy
. cancel
) } else { decisionHandler ( WKNavigationActionPolicy
. allow
) } }
③ 非法跳轉請求攔截
非法跳轉請求攔截就是由網頁發出一條新的跳轉請求,跳轉的目的地是一個非法的壓根就不存在的地址,比如:
https
: dwdwdw
:
url 地址組成如下: 協議:也就是 http/https/file 等,非法請求通信地址用了 dwdwdw; 域名:上面的 .baidu.com 或 yangdw; 參數:上面的 xx=xx 或 param=paramobj; 如果構建一條假 url: 客戶端會無差別攔截所有請求,真正的 url 地址應該照常放過,只有協議域名匹配的 url 地址才應該被客戶端攔截,攔截下來的 url 不會導致 WebView 繼續跳轉錯誤地址,因此無感知,相反攔截下來的 url 可以讀取其中路徑當做指令,讀取其中參數當做數據,從而根據約定調用對應的 Native 原生代碼。 以上其實是一種協議約定,只要 JS 按著這個約定協議生成假 url,Native 按著約定協議攔截/讀取假 url,整個流程就能跑通。
三、User-Agent 設置
① 全局設置
App 內所有 Web 請求的 User-Agent 全部被修改:
let webView
= UIWebView ( frame
: CGRect
. zero
) let userAgent
= webView
. stringByEvaluatingJavaScript ( from
: "navigator.userAgent" ) if let agent
= userAgent
{ let user
= "@\(agent);extra_user_agent" let dict
= [ "UserAgent" : user
] UserDefaults
. standard
. register ( defaults
: dict
) } let webV
= WKWebView ( frame
: CGRect
. zero
) webV
. evaluateJavaScript ( "navigator.userAgent" ) { ( result
, error
) in if let oldAgent
= result as
? String
{ let user
= "@\(oldAgent);extra_user_agent" let dict
= [ "UserAgent" : user
] UserDefaults
. standard
. register ( defaults
: dict
) } }
② 單個 WebView 設置
在 iOS9,WKWebView 提供了一個非常便捷的屬性去更改 User-Agent,就是 customUserAgent 屬性,這樣使用起來不僅方便,也不會全局更改 User-Agent,可惜的是 iOS9 才有,如果適配 iOS8,還是需要使用上面的方法。
let webView
= UIWebView ( frame
: CGRect
. zero
) let userAgent
= webView
. stringByEvaluatingJavaScript ( from
: "navigator.userAgent" ) if let agent
= userAgent
{ let user
= "@\(agent);extra_user_agent" webView
. customUserAgent
= user
}
總結
以上是生活随笔 為你收集整理的iOS之深入解析WKWebView的坑点收录和优化处理 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。