我可以设置WKWebView使用的cookie吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我可以设置WKWebView使用的cookie吗?相关的知识,希望对你有一定的参考价值。

我正在尝试将现有的应用程序从UIWebView切换到WKWebView。当前应用程序管理webview之外的用户登录/会话,并将认证所需的cookies设置为NSHTTPCookieStore。不幸的是,新的WKWebView不使用cookiesNSHTTPCookieStorage。还有另一种方法来实现这一目标吗?

答案

仅适用于ios 11+

使用WKHTTPCookieStore

let cookie = HTTPCookie(properties: [
    .domain: "example.com",
    .path: "/",
    .name: "MyCookieName",
    .value: "MyCookieValue",
    .secure: "TRUE",
    .expires: NSDate(timeIntervalSinceNow: 31556926)
])! 

webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie)

由于您是从HTTPCookeStorage中提取它们,因此可以执行以下操作:

let cookies = HTTPCookieStorage.shared.cookies ?? []
for (cookie) in cookies {
    webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie)
}

适用于iOS 10及以下版本的旧答案

如果您需要在初始加载请求中设置cookie,可以在NSMutableURLRequest上设置它们。因为cookie只是一个特殊格式的请求标头,所以可以这样实现:

WKWebView * webView = /*set up your webView*/
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com/index.html"]];
[request addValue:@"TeskCookieKey1=TeskCookieValue1;TeskCookieKey2=TeskCookieValue2;" forHTTPHeaderField:@"Cookie"];
// use stringWithFormat: in the above line to inject your values programmatically
[webView loadRequest:request];

如果您要求页面上的后续AJAX请求设置其cookie,可以通过简单地使用WKUserScript在文档启动时通过javascript以编程方式设置值来实现,如下所示:

WKUserContentController* userContentController = WKUserContentController.new;
WKUserScript * cookieScript = [[WKUserScript alloc] 
    initWithSource: @"document.cookie = 'TeskCookieKey1=TeskCookieValue1';document.cookie = 'TeskCookieKey2=TeskCookieValue2';"
    injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
// again, use stringWithFormat: in the above line to inject your values programmatically
[userContentController addUserScript:cookieScript];
WKWebViewConfiguration* webViewConfig = WKWebViewConfiguration.new;
webViewConfig.userContentController = userContentController;
WKWebView * webView = [[WKWebView alloc] initWithFrame:CGRectMake(/*set your values*/) configuration:webViewConfig];

结合这两种技术应该为您提供足够的工具来将Cookie值从Native App Land传输到Web View Land。如果您需要更高级的cookie,可以在cookie javascript API on Mozilla's page上找到更多信息。

是的,苹果不支持许多the niceties of UIWebView很糟糕。不确定他们是否会支持他们,但希望他们能尽快得到这个。希望这可以帮助!

另一答案

发布此答案背后的原因是我尝试了很多解决方案,但没有人正常工作,大多数答案不适用于必须首次设置cookie,并且第一次得到结果cookie不同步,请使用此解决方案它适用于两者iOS> = 11.0 <= iOS 11至8.0,也可以首次使用cookie同步。

对于iOS> = 11.0 - Swift 4.2

获取http cookie并以这种方式设置在wkwebview cookie商店中,在wkwebview中加载你的请求非常棘手,必须在完全设置cookie时发送加载请求,这是我写的功能。

在调用加载webview时完成闭包的调用函数。仅供参考此功能仅处理iOS> = 11.0

self.WwebView.syncCookies {
    if let request = self.request {
       self.WwebView.load(request)
    }
}

这是syncCookies函数的实现。

func syncCookies(completion:@escaping ()->Void) {

if #available(iOS 11.0, *) {

      if let yourCookie = "HERE_YOUR_HTTP_COOKIE_OBJECT" {
        self.configuration.websiteDataStore.httpCookieStore.setCookie(yourCookie, completionHandler: {
              completion()
        })
     }
  } else {
  //Falback just sent 
  completion()
}
}

适用于iOS 8至iOS 11

你需要设置一些额外的东西,你需要通过使用WKUserScript设置两个时间cookie,并且不要忘记在请求中添加cookie,否则你的cookie不会第一次同步,你会看到你的页面没有正确加载第一次。这是我发现支持iOS 8.0的cookie的哎呀

在你创建Wkwebview对象之前。

func setUpWebView() {

    let userController: WKUserContentController = WKUserContentController.init()

    if IOSVersion.SYSTEM_VERSION_LESS_THAN(version: "11.0") {
        if let cookies = HTTPCookieStorage.shared.cookies {
            if let script = getJSCookiesString(for: cookies) {
                cookieScript = WKUserScript(source: script, injectionTime: .atDocumentStart, forMainFrameOnly: false)
                userController.addUserScript(cookieScript!)
            }
        }
    }

    let webConfiguration = WKWebViewConfiguration()
    webConfiguration.processPool = BaseWebViewController.processPool


    webConfiguration.userContentController = userController


    let customFrame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: 0.0, height: self.webContainerView.frame.size.height))
    self.WwebView = WKWebView (frame: customFrame, configuration: webConfiguration)
    self.WwebView.translatesAutoresizingMaskIntoConstraints = false
    self.webContainerView.addSubview(self.WwebView)
    self.WwebView.uiDelegate = self
    self.WwebView.navigationDelegate = self
    self.WwebView.allowsBackForwardNavigationGestures = true // A Boolean value indicating whether horizontal swipe gestures will trigger back-forward list navigations
    self.WwebView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)


 self.view.addConstraint(NSLayoutConstraint(item: WwebView, attribute: .trailing, relatedBy: .equal, toItem: self.webContainerView, attribute: .trailing, multiplier: 1, constant: 0))
    self.view.addConstraint(NSLayoutConstraint(item: WwebView, attribute: .leading, relatedBy: .equal, toItem: self.webContainerView, attribute: .leading, multiplier: 1, constant: 0))
    self.view.addConstraint(NSLayoutConstraint(item: WwebView, attribute: .top, relatedBy: .equal, toItem: self.webContainerView, attribute: .top, multiplier: 1, constant: 0))
    self.view.addConstraint(NSLayoutConstraint(item: WwebView, attribute: .bottom, relatedBy: .equal, toItem: self.webContainerView, attribute: .bottom, multiplier: 1, constant: 0))


}

专注于此函数getJSCookiesString

 public func getJSCookiesString(for cookies: [HTTPCookie]) -> String? {

    var result = ""
    let dateFormatter = DateFormatter()
    dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
    dateFormatter.dateFormat = "EEE, d MMM yyyy HH:mm:ss zzz"

    for cookie in cookies {
        if cookie.name == "yout_cookie_name_want_to_sync" {
            result += "document.cookie='(cookie.name)=(cookie.value); domain=(cookie.domain); path=(cookie.path); "
            if let date = cookie.expiresDate {
                result += "expires=(dateFormatter.string(from: date)); "
            }
            if (cookie.isSecure) {
                result += "secure; "
            }
            result += "'; "
        }

    }

    return result
}

这里是其他步骤wkuserscript不能立即同步cookie,有很多加载第一次使用cookie的页面,如果它终止进程但是我不建议使用它再次重新加载webview,它不利于用户的观点,heck是每当你准备好在请求头中加载请求集cookie时也是这样,不要忘记添加iOS版本检查。在加载请求之前调用此函数。

request?.addCookies()

我为URLRequest写了扩展名

extension URLRequest {

internal mutating func addCookies() {
    //"appCode=anAuY28ucmFrdXRlbi5yZXdhcmQuaW9zLXpOQlRTRmNiejNHSzR0S0xuMGFRb0NjbUg4Ql9JVWJH;rpga=kW69IPVSYZTo0JkZBicUnFxC1g5FtoHwdln59Z5RNXgJoMToSBW4xAMqtf0YDfto;rewardadid=D9F8CE68-CF18-4EE6-A076-CC951A4301F6;rewardheader=true"
    var cookiesStr: String = ""

    if IOSVersion.SYSTEM_VERSION_LESS_THAN(version: "11.0") {
        let mutableRequest = ((self as NSURLRequest).mutableCopy() as? NSMutableURLRequest)!
        if let yourCookie = "YOUR_HTTP_COOKIE_OBJECT" {
            // if have more than one cookies dont forget to add ";" at end
            cookiesStr += yourCookie.name + "=" + yourCookie.value + ";"

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

        }
    }

  }
}

现在你准备去测试iOS> 8了

另一答案

请找到最有可能为您提供解决方案的解决方案。基本上它是为Swift 4 @ user3589213的iOS开发:WKWebView的使用(设置cookie、不受信任的HTTPS、返回关闭按钮)

iOS 和 H5 页面交互(WKWebview 和 UIWebview cookie 设置)

如何从 WKWebView 启用和获取 cookie?

更改为WKWebView后在NSURLRequest上缺少一些cookie

electron webview有办法获取到cookie吗

如何在没有 JavaScript 的情况下将 cookie 注入 WKWebView 或 WKWebSiteDataStore?