日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

iOS之深入解析WKWebView的坑点收录和优化处理

發(fā)布時間:2024/5/21 编程问答 73 豆豆
生活随笔 收集整理的這篇文章主要介紹了 iOS之深入解析WKWebView的坑点收录和优化处理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、Cookie 處理

① Cookie 說明

  • WKWebView 在設(shè)置 Cookie 的時候,經(jīng)常做的是在請求的請求頭里添加 Cookie,但這只是把 Cookie 發(fā)送給了服務(wù)端,本地并沒有保存 Cookie,Cookie 最終要寫到 WebView 的一個 Cookie 文件目錄里面,后續(xù) WebView 里面自己的發(fā)起的請求或者跳轉(zhuǎn)才能在發(fā)起請求的時候,在對應(yīng)的域名下面取到 Cookie 傳出去。
  • Webview 加載 H5 頁面,實際上是把頁面相關(guān)的 .html、js、css 文件下載到本地,然后再加載,這時頁面去獲取 Cookie 的時候,是去本地 WebView 里的 Cookie 文件目錄里查找,如果沒有設(shè)置的話肯定就獲取不到,所以在設(shè)置 Cookie 的時候,服務(wù)端和客戶端都要設(shè)置。
② 服務(wù)端 Cookie 設(shè)置
  • 在使用 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 發(fā)起的請求不會自動帶上存儲于 NSHTTPCookieStorage 容器中的 Cookie。解決辦法也很簡單,就是在 WKWebView 發(fā)起請求之前,先從 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")
  • 當(dāng)服務(wù)器頁面發(fā)生重定向的時候,此時第一次在 RequestHeader 中寫入的 Cookie 會丟失,還需要對重定向的請求重新做添加 Cookie 的處理。

② 客戶端 Cookie 設(shè)置

  • 當(dāng)頁面加載的時候,后端無論是啥語言,都能從請求頭里看到 Cookie 了,但是后端渲染返回頁面后,在客戶端的 WebView 里運行的時候,JS 在執(zhí)行的時候調(diào)用 document.cookie API 是讀取不到 Cookie 的,所以還得針對客戶端 Cookie 進(jìn)行處理:
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 注入實際上就是創(chuàng)建一個 JS 腳本,讓 WebView 去執(zhí)行,推薦在 .atDocumentStart 這個時機進(jìn)行預(yù)置靜態(tài) JS 的注入,這樣 WebView 在加載后端返回的靜態(tài)頁面的時候,就可以拿到保存著客戶端的 Cookie 了。

二、URL 攔截

① Web 頁面重定向問題

  • 在 WKWebView 中,每一次頁面跳轉(zhuǎn)之前,都會調(diào)用下面的回調(diào)函數(shù):
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
  • 重定向問題有兩種:
    • 服務(wù)器頁面重定向,需要對新發(fā)起的請求重新設(shè)置 Cookie;
    • 本地頁面重定向,只要客戶端設(shè)置了 Cookie,那么就不需要再處理。
  • 因此,如果是服務(wù)器頁面重定向,那么判斷此時 Request 是否有需要的 Cookie,沒有就 Cancel 掉,修改 Request 重新發(fā)起。
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void){var shouldCancelLoadURL = falseif 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 = falseif let url = navigationAction.request.url?.absoluteString {if url.contains("baidu.tech") { // 原來的域名shouldCancelLoadURL = false} else {// 重新發(fā)起請求,種CookieshouldCancelLoadURL = true}} else {// 重新發(fā)起請求,種CookieshouldCancelLoadURL = true}if shouldCancelLoadURL {decisionHandler(WKNavigationActionPolicy.cancel)} else {decisionHandler(WKNavigationActionPolicy.allow)}}

③ 非法跳轉(zhuǎn)請求攔截

  • 非法跳轉(zhuǎn)請求攔截就是由網(wǎng)頁發(fā)出一條新的跳轉(zhuǎn)請求,跳轉(zhuǎn)的目的地是一個非法的壓根就不存在的地址,比如:
// 常規(guī)的Http地址https://baidu.com/xxxx?xx=xx// 非法請求通信地址dwdwdw://yangdw/action?param=paramobj
  • url 地址組成如下:
    • 協(xié)議:也就是 http/https/file 等,非法請求通信地址用了 dwdwdw;
    • 域名:上面的 .baidu.com 或 yangdw;
    • 路徑:上面的 xxxx? 或 action?;
    • 參數(shù):上面的 xx=xx 或 param=paramobj;
  • 如果構(gòu)建一條假 url:
    • 用協(xié)議與域名當(dāng)做通信識別;
    • 用路徑當(dāng)做指令識別;
    • 用參數(shù)當(dāng)做數(shù)據(jù)傳遞;
  • 客戶端會無差別攔截所有請求,真正的 url 地址應(yīng)該照常放過,只有協(xié)議域名匹配的 url 地址才應(yīng)該被客戶端攔截,攔截下來的 url 不會導(dǎo)致 WebView 繼續(xù)跳轉(zhuǎn)錯誤地址,因此無感知,相反攔截下來的 url 可以讀取其中路徑當(dāng)做指令,讀取其中參數(shù)當(dāng)做數(shù)據(jù),從而根據(jù)約定調(diào)用對應(yīng)的 Native 原生代碼。
  • 以上其實是一種協(xié)議約定,只要 JS 按著這個約定協(xié)議生成假 url,Native 按著約定協(xié)議攔截/讀取假 url,整個流程就能跑通。

三、User-Agent 設(shè)置

① 全局設(shè)置

  • App 內(nèi)所有 Web 請求的 User-Agent 全部被修改:
// UIWebViewlet 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)}// WKWebViewlet webV = WKWebView(frame: CGRect.zero)webV.evaluateJavaScript("navigator.userAgent") { (result, error) inif let oldAgent = result as? String {let user = "@\(oldAgent);extra_user_agent"let dict = ["UserAgent":user]UserDefaults.standard.register(defaults: dict)}}

② 單個 WebView 設(shè)置

  • 在 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}

總結(jié)

以上是生活随笔為你收集整理的iOS之深入解析WKWebView的坑点收录和优化处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。