【问题标题】:WKWebView setting Cookie not possible (iOS 11+)WKWebView 无法设置 Cookie (iOS 11+)
【发布时间】:2018-12-01 03:06:48
【问题描述】:

我正在拼命尝试将自定义 cookie 添加到 WKWebView 实例(不使用 Javascript 或类似的解决方法)。

从 iOS 11 及更高版本开始,Apple 提供了一个 API 来执行此操作:WKWebViews WKWebsiteDataStore 有一个属性 httpCookieStore

这是我的(示例)代码:

import UIKit
import WebKit

class ViewController: UIViewController {

    var webView: WKWebView!

    override func viewDidLoad() {
        webView = WKWebView()
        view.addSubview(webView)
        super.viewDidLoad()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        let cookie = HTTPCookie(properties: [
            HTTPCookiePropertyKey.domain : "google.com",
            HTTPCookiePropertyKey.path : "/",
            HTTPCookiePropertyKey.secure : true,
            HTTPCookiePropertyKey.name : "someCookieKey",
            HTTPCookiePropertyKey.value : "someCookieValue"])!

        let cookieStore = webView.configuration.websiteDataStore.httpCookieStore
        cookieStore.setCookie(cookie) {
            DispatchQueue.main.async {
                self.webView.load(URLRequest(url: URL(string: "https://google.com")!))
            }
        }
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        webView.frame = view.bounds
    }
}

在此之后,如果我使用 webView.configuration.websiteDataStore.httpCookieStore.getAllCookies(completionHandler:),我会看到我的 cookie 在 cookie 列表中。

但是,当使用 Safari 的开发人员工具(当然是使用 iOS 模拟器)检查 webview 时,cookie 不会显示。

我还尝试使用 HTTP 代理(在我的例子中是 Charles)检查流量,以查看我的 HTTP 请求中是否包含 cookie。不是。

我在这里做错了什么?如何将 cookie 添加到 WKWebView(在 iOS 版本 11 及更高版本上)?

【问题讨论】:

  • 别以为你能做到。 Safaris 有自己的数据存储。因此,cookie、本地存储...不会在您的 webview 实例和 Safari 之间共享。这就是你在 Sarafi 看不到它们的原因
  • 请再次阅读我的问题。我正在将 Safaris 调试器附加到我的 WKWebView。
  • 啊,我的错。无论如何,您设置了 cookie,但没有将 cookie 与 URLRequest 对象一起发送。你应该做类似 urlRequest.setValue("someCookieKey = someCookieValue", forHTTPHeaderField: "Cookie")
  • 我为什么需要这样做?如果设置了 cookie,它应该包含在 WKWebView 发出的任何请求中。如果不是,那老实说就是一个障碍。虽然我可以像您展示的那样为初始请求设置标头,但我无法为任何后续(ajax)请求设置标头,从而破坏了 cookie 的目的。
  • 啊,好问题,如果你想让它自动附加cookie,只需urlRequest. HTTPShouldHandleCookies = true

标签: ios cookies wkwebview wkhttpcookiestore


【解决方案1】:

有点晚了,但我想分享一个对我有用的解决方案,我希望它对在 iOS 12 上也面临同样问题的人有所帮助。

这是我使用的简化工作流程:

  1. 实例化 WKWebsiteDataStore 对象
  2. 将自定义 cookie 设置为其 httpCookieStore
  3. 等待设置 cookie
  4. 实例化 WKWebView
  5. 加载请求

为此,我创建了 WKWebViewConfiguration 的扩展:

extension WKWebViewConfiguration {

static func includeCookie(cookie:HTTPCookie, preferences:WKPreferences, completion: @escaping (WKWebViewConfiguration?) -> Void) {
     let config = WKWebViewConfiguration()
     config.preferences = preferences

     let dataStore = WKWebsiteDataStore.nonPersistent()

     DispatchQueue.main.async {
        let waitGroup = DispatchGroup()

        waitGroup.enter()
        dataStore.httpCookieStore.setCookie(cookie) {
            waitGroup.leave()
        }

        waitGroup.notify(queue: DispatchQueue.main) {
            config.websiteDataStore = dataStore
            completion(config)
        }
    }
}

对于我的例子,我使用它如下:

override func viewDidLoad() {
  self.AddWebView()
}

private func addWebView(){

    let preferences = WKPreferences()
    preferences.javaScriptEnabled = true
    preferences.javaScriptCanOpenWindowsAutomatically = true

    let cookie = HTTPCookie(properties: [
        .domain: COOKIE_DOMAIN,
        .path: "/",
        .name: COOKIE_NAME,
        .value: myCookieValue,
        .secure: "TRUE",
        .expires: NSDate(timeIntervalSinceNow: 3600)
        ])

     //Makes sure the cookie is set before instantiating the webview and initiating the request
     if let myCookie = cookie {
        WKWebViewConfiguration.includeCookie(cookie: myCookie, preferences: preferences, completion: {
           [weak self] config in
              if let `self` = self {
                 if let configuration = config {
                    self.webView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width , height: self.view.frame.height), configuration: configuration)

                    self.view.addSubview(self.webView)
                    self.webView.load(self.customRequest)
                 }
              }
     }
}

【讨论】:

  • 很好的答案,谢谢。我还添加了一个 cookie 数组设置器。
  • 在 2020 年的 iOS 13 上像魅力一样工作,谢谢先生!
  • 嗯。现在我发现会话cookie只能存储在nonPersistant数据存储中。
  • 您好 SwissMark,您能否也分享一下如何在 SwiftUI 中实现它?
【解决方案2】:

google.com 的任何请求都会重定向到www.google.com

您需要将www. 添加到cookie 的域字段中。如果域或路径与请求不匹配,则不会发送 cookie。

您可以显式添加 cookie。

let url = URL(string: "https://www.google.com")!
var request = URLRequest(url: url)
if let cookies = HTTPCookieStorage.shared.cookies(for: url) {
    request.allHTTPHeaderFields = HTTPCookie.requestHeaderFields(with: cookies)
}
self.webView.load(request)

【讨论】:

  • 这对我不起作用。该 cookie 仍未添加到请求中,并且似乎在 WKWebViews 存储中不可用(使用 Safari 开发工具检查)。
  • 我用显式方法更新了答案以设置 cookie。可能有更好的解决方案,但这应该能让你继续前进。
  • 感谢您的回答!不幸的是,这只设置了这个请求的 cookie。我试图嵌入的 WebApp(google.com 只是一个例子)使用后续的 AJAX 请求,这也需要应用 cookie。因此,很遗憾我不能采纳你的建议。
  • @Onato 不需要添加 www。一开始是因为当您在 safari 上进行检查时,它没有显示它是否通过 www。
【解决方案3】:

对于 iOS 11+,您真的不需要担心 cookie 部分,这非常简单。像这样创建你的 cookie。不要让它安全true

let newcookie = HTTPCookie(properties: [
        .domain: "domain",
        .path: "/",
        .name: "name",
        .value: "vale",
        .secure: "FALSE",
        .expires: NSDate(timeIntervalSinceNow: 31556926)
        ])!

self.webview.configuration.websiteDataStore.httpCookieStore.setCookie(newcookie, completionHandler: {
                        // completion load your url request here. Better to add cookie in Request as well. like this way
       request.addCookies()
//enable cookie through request
        request.httpShouldHandleCookies = true

//load request in your webview.


                    })

请求扩展在cookie值之后添加";"

extension URLRequest {

internal mutating func addCookies() {
    var cookiesStr: String = ""

        let mutableRequest = ((self as NSURLRequest).mutableCopy() as? NSMutableURLRequest)!
            cookiesStr += cookie.name + "=" + cookie.value + ";"                

            mutableRequest.setValue(cookiesStr, forHTTPHeaderField: "Cookie")
            self = mutableRequest as URLRequest

     }

}

我还可以看到您没有设置 wkwebview 的 WKWebViewConfiguration。设置 wkwebview 的配置。同时实现WKHTTPCookieStoreObserver并实现函数。

    func cookiesDidChange(in cookieStore: WKHTTPCookieStore) {
    // Must implement otherwise wkwebview cookie not sync properly
    self.httpCookieStore.getAllCookies { (cookies) in
        cookies.forEach({ (cookie) in

        })
    }
}

希望这会奏效。

【讨论】:

  • 嗨 Shauket,您能否也展示一个 SwiftUI 中的示例实现?谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-23
  • 1970-01-01
  • 2017-11-18
  • 2022-09-27
  • 2018-02-05
  • 2018-11-28
  • 2019-03-19
相关资源
最近更新 更多