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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26573137/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 03:22:14  来源:igfitidea点击:

Can I set the cookies to be used by a WKWebView?

ioscookiesuiwebviewios8wkwebview

提问by Col

I'm trying to switch an existing app from UIWebViewto WKWebView. The current app manages the users login / session outside of the webviewand sets the cookiesrequired for authentication into the the NSHTTPCookieStore. Unfortunately new WKWebViewdoesn't use the cookiesfrom the NSHTTPCookieStorage. Is there another way to achieve this?

我正在尝试将现有应用程序从 切换UIWebViewWKWebView。目前的应用程序管理的用户登录/会话外webview,并设置cookies需要进行身份验证到的NSHTTPCookieStore。不幸的是 newWKWebView不使用cookies来自NSHTTPCookieStorage. 有没有另一种方法来实现这一目标?

回答by mattr

Edit for iOS 11+ only

仅针对 iOS 11+ 进行编辑

Use WKHTTPCookieStore:

使用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)

Since you are pulling them over from HTTPCookeStorage, you can do this:

由于您是从 HTTPCookeStorage 中提取它们,您可以这样做:

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

Old answer for iOS 10 and below

iOS 10 及更低版本的旧答案

If you require your cookies to be set on the initial load request, you can set them on NSMutableURLRequest. Because cookies are just a specially formatted request header this can be achieved like so:

如果您需要在初始加载请求上设置 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];

If you require subsequent AJAX requests on the page to have their cookies set, this can be achieved by simply using WKUserScript to set the values programmatically via javascript at document start like so:

如果您需要页面上的后续 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];

Combining these two techniques should give you enough tools to transfer cookie values from Native App Land to Web View Land. You can find more info on the cookie javascript API on Mozilla's pageif you require some more advanced cookies.

结合这两种技术,您应该有足够的工具将 cookie 值从 Native App Land 传输到 Web View Land。如果您需要一些更高级的 cookie,您可以在 Mozilla 页面上的cookie javascript API 上找到更多信息。

Yeah, it sucks that Apple is not supporting many of the niceties of UIWebView. Not sure if they will ever support them, but hopefully they will get on this soon. Hope this helps!

是的,Apple 不支持UIWebView 的许多细节,这很糟糕。不确定他们是否会支持他们,但希望他们能尽快开始。希望这可以帮助!

回答by deanWombourne

After playing with this answer(which was fantastically helpful :) we've had to make a few changes:

在玩过这个答案(这非常有帮助:) 之后,我们不得不做一些改变:

  • We need web views to deal with multiple domains without leaking private cookie information between those domains
  • We need it to honour secure cookies
  • If the server changes a cookie value we want our app to know about it in NSHTTPCookieStorage
  • If the server changes a cookie value we don't want our scripts to reset it back to its original value when you follow a link / AJAX etc.
  • 我们需要 web 视图来处理多个域,而不会泄露这些域之间的私有 cookie 信息
  • 我们需要它来兑现安全 cookie
  • 如果服务器更改了 cookie 值,我们希望我们的应用程序在 NSHTTPCookieStorage
  • 如果服务器更改了 cookie 值,我们不希望我们的脚本在您点击链接/AJAX 等时将其重置回其原始值。

So we modified our code to be this;

所以我们把我们的代码修改成这样;

Creating a request

创建请求

NSMutableURLRequest *request = [originalRequest mutableCopy];
NSString *validDomain = request.URL.host;
const BOOL requestIsSecure = [request.URL.scheme isEqualToString:@"https"];

NSMutableArray *array = [NSMutableArray array];
for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
    // Don't even bother with values containing a `'`
    if ([cookie.name rangeOfString:@"'"].location != NSNotFound) {
        NSLog(@"Skipping %@ because it contains a '", cookie.properties);
        continue;
    }

    // Is the cookie for current domain?
    if (![cookie.domain hasSuffix:validDomain]) {
        NSLog(@"Skipping %@ (because not %@)", cookie.properties, validDomain);
        continue;
    }

    // Are we secure only?
    if (cookie.secure && !requestIsSecure) {
        NSLog(@"Skipping %@ (because %@ not secure)", cookie.properties, request.URL.absoluteString);
        continue;
    }

    NSString *value = [NSString stringWithFormat:@"%@=%@", cookie.name, cookie.value];
    [array addObject:value];
}

NSString *header = [array componentsJoinedByString:@";"];
[request setValue:header forHTTPHeaderField:@"Cookie"];

// Now perform the request...

This makes sure that the first request has the correct cookies set, without sending any cookies from the shared storage that are for other domains, and without sending any secure cookies into an insecure request.

这可确保第一个请求设置了正确的 cookie,不会从共享存储中发送任何用于其他域的 cookie,也不会将任何安全 cookie 发送到不安全的请求中。

Dealing with further requests

处理进一步的请求

We also need to make sure that other requests have the cookies set. This is done using a script that runs on document load which checks to see if there is a cookie set and if not, set it to the value in NSHTTPCookieStorage.

我们还需要确保其他请求设置了 cookie。这是使用在文档加载时运行的脚本完成的,该脚本检查是否有 cookie 集,如果没有,则将其设置为 中的值NSHTTPCookieStorage

// Get the currently set cookie names in javascriptland
[script appendString:@"var cookieNames = document.cookie.split('; ').map(function(cookie) { return cookie.split('=')[0] } );\n"];

for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
    // Skip cookies that will break our script
    if ([cookie.value rangeOfString:@"'"].location != NSNotFound) {
        continue;
    }

    // Create a line that appends this cookie to the web view's document's cookies
    [script appendFormat:@"if (cookieNames.indexOf('%@') == -1) { document.cookie='%@'; };\n", cookie.name, cookie.wn_javascriptString];
}

WKUserContentController *userContentController = [[WKUserContentController alloc] init];
WKUserScript *cookieInScript = [[WKUserScript alloc] initWithSource:script
                                                      injectionTime:WKUserScriptInjectionTimeAtDocumentStart
                                                   forMainFrameOnly:NO];
[userContentController addUserScript:cookieInScript];

...

...

// Create a config out of that userContentController and specify it when we create our web view.
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.userContentController = userContentController;

self.webView = [[WKWebView alloc] initWithFrame:webView.bounds configuration:config];

Dealing with cookie changes

处理 cookie 更改

We also need to deal with the server changing a cookie's value. This means adding another script to call back out of the web view we are creating to update our NSHTTPCookieStorage.

我们还需要处理服务器更改 cookie 的值。这意味着添加另一个脚本来回调我们正在创建的 Web 视图以更新我们的NSHTTPCookieStorage.

WKUserScript *cookieOutScript = [[WKUserScript alloc] initWithSource:@"window.webkit.messageHandlers.updateCookies.postMessage(document.cookie);"
                                                       injectionTime:WKUserScriptInjectionTimeAtDocumentStart
                                                    forMainFrameOnly:NO];
[userContentController addUserScript:cookieOutScript];

[userContentController addScriptMessageHandler:webView
                                          name:@"updateCookies"];

and implementing the delegate method to update any cookies that have changed, making sure that we are only updating cookies from the current domain!

并实现委托方法来更新任何已更改的 cookie,确保我们只更新来自当前域的 cookie!

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    NSArray<NSString *> *cookies = [message.body componentsSeparatedByString:@"; "];
    for (NSString *cookie in cookies) {
        // Get this cookie's name and value
        NSArray<NSString *> *comps = [cookie componentsSeparatedByString:@"="];
        if (comps.count < 2) {
            continue;
        }

        // Get the cookie in shared storage with that name
        NSHTTPCookie *localCookie = nil;
        for (NSHTTPCookie *c in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:self.wk_webView.URL]) {
            if ([c.name isEqualToString:comps[0]]) {
                localCookie = c;
                break;
            }
        }

        // If there is a cookie with a stale value, update it now.
        if (localCookie) {
            NSMutableDictionary *props = [localCookie.properties mutableCopy];
            props[NSHTTPCookieValue] = comps[1];
            NSHTTPCookie *updatedCookie = [NSHTTPCookie cookieWithProperties:props];
            [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:updatedCookie];
        }
    }
}

This seems to fix our cookie problems without us having to deal with each place we use WKWebView differently. We can now just use this code as a helper to create our web views and it transparently updates NSHTTPCookieStoragefor us.

这似乎解决了我们的 cookie 问题,而我们不必以不同的方式处理我们使用 WKWebView 的每个地方。我们现在可以使用此代码作为帮助程序来创建我们的 Web 视图,它会NSHTTPCookieStorage为我们透明地更新。



EDIT: Turns out I used a private category on NSHTTPCookie - here's the code:

编辑:原来我在 NSHTTPCookie 上使用了一个私有类别 - 这是代码:

- (NSString *)wn_javascriptString {
    NSString *string = [NSString stringWithFormat:@"%@=%@;domain=%@;path=%@",
                        self.name,
                        self.value,
                        self.domain,
                        self.path ?: @"/"];

    if (self.secure) {
        string = [string stringByAppendingString:@";secure=true"];
    }

    return string;
}

回答by nteissler

The cookies must be set on the configuration before the WKWebViewis created. Otherwise, even with WKHTTPCookieStore's setCookiecompletion handler, the cookies won't reliably be synced to the web view. This goes back to this line from the docson WKWebViewConfiguration

在创建 cookie 之前,必须在配置上设置 cookie WKWebView。否则,即使使用WKHTTPCookieStoresetCookie完成处理程序,cookie 也不会可靠地同步到 Web 视图。这又从背部到这一行的文档WKWebViewConfiguration

@NSCopying var configuration: WKWebViewConfiguration { get }
@NSCopying var configuration: WKWebViewConfiguration { get }

That @NSCopyingis somewhat of a deep copy. The implementation is beyond me, but the end result is that unless you set cookies before initializing the webview, you can't count on the cookies being there. This can complicate app architecture because initializing a view becomes an asynchronous process. You'll end up with something like this

@NSCopying有点深拷贝。实现超出了我的范围,但最终结果是,除非您在初始化 webview 之前设置 cookie,否则您不能指望那里有 cookie。这会使应用程序架构复杂化,因为初始化视图变成了一个异步过程。你会得到这样的结果

extension WKWebViewConfiguration {
    /// Async Factory method to acquire WKWebViewConfigurations packaged with system cookies
    static func cookiesIncluded(completion: @escaping (WKWebViewConfiguration?) -> Void) {
        let config = WKWebViewConfiguration()
        guard let cookies = HTTPCookieStorage.shared.cookies else {
            completion(config)
            return
        }
        // Use nonPersistent() or default() depending on if you want cookies persisted to disk
        // and shared between WKWebViews of the same app (default), or not persisted and not shared
        // across WKWebViews in the same app.
        let dataStore = WKWebsiteDataStore.nonPersistent()
        let waitGroup = DispatchGroup()
        for cookie in cookies {
            waitGroup.enter()
            dataStore.httpCookieStore.setCookie(cookie) { waitGroup.leave() }
        }
        waitGroup.notify(queue: DispatchQueue.main) {
            config.websiteDataStore = dataStore
            completion(config)
        }
    }
}

and then to use it something like

然后使用它像

override func loadView() {
    view = UIView()
    WKWebViewConfiguration.cookiesIncluded { [weak self] config in
        let webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.load(request)
        self.view = webView
    }
}

The above example defers view creation until the last possible moment, another solution would be to create the config or webview well in advance and handle the asynchronous nature before creation of a view controller.

上面的示例将视图创建推迟到最后一刻,另一种解决方案是提前创建配置或 webview,并在创建视图控制器之前处理异步性质。

A final note: once you create this webview, you have set it loose into the wild, you can't add more cookies without using methods described in this answer. You can however use the WKHTTPCookieStoreObserverapi to at least observe changes happening to cookies. So if a session cookie gets updated in the webview, you can manually update the system's HTTPCookieStoragewith this new cookie if desired.

最后一点:一旦你创建了这个 webview,你就已经把它放开了,如果不使用这个答案中描述的方法,你就不能添加更多的 cookie 。但是,您可以使用WKHTTPCookieStoreObserverapi 至少观察 cookie 发生的变化。因此,如果会话 cookie 在 webview 中更新,您可以HTTPCookieStorage根据需要使用此新 cookie手动更新系统。

For more on this, skip to 18:00 at this 2017 WWDC Session Custom Web Content Loading. At the beginning of this session, there is a deceptive code sample which omits the fact that the webview should be created in the completion handler.

有关更多信息,请跳至2017 年 WWDC 会话自定义 Web 内容加载的18:00 。在这个会话的开始,有一个欺骗性的代码示例,它省略了 webview 应该在完成处理程序中创建的事实。

cookieStore.setCookie(cookie!) {
    webView.load(loggedInURLRequest)
}

The live demo at 18:00 clarifies this.

18:00 的现场演示澄清了这一点。

EditAs of Mojave Beta 7 and iOS 12 Beta 7 at least, I'm seeing much more consistent behavior with cookies. The setCookie(_:)method even appears to allow setting cookies after the WKWebViewhas been created. I did find it important though, to not touchthe processPoolvariable at all. The cookie setting functionality works best when no additional pools are created and when that property is left well alone. I think it's safe to say we were having issues due to some bugs in WebKit.

编辑莫哈韦7 Beta版和iOS测试版12 7的作为至少,我看到与cookies更加一致的行为。该setCookie(_:)方法甚至似乎允许WKWebView在创建后设置 cookie 。我发现它的重要,虽然,以不碰processPool所有变量。当没有创建额外的池并且该属性被单独保留时,cookie 设置功能最有效。我认为可以肯定地说,由于 WebKit 中的一些错误,我们遇到了问题。

回答by user3589213

work for me

为我工作

func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
    let headerFields = navigationAction.request.allHTTPHeaderFields
    var headerIsPresent = contains(headerFields?.keys.array as! [String], "Cookie")

    if headerIsPresent {
        decisionHandler(WKNavigationActionPolicy.Allow)
    } else {
        let req = NSMutableURLRequest(URL: navigationAction.request.URL!)
        let cookies = yourCookieData
        let values = NSHTTPCookie.requestHeaderFieldsWithCookies(cookies)
        req.allHTTPHeaderFields = values
        webView.loadRequest(req)

        decisionHandler(WKNavigationActionPolicy.Cancel)
    }
}

回答by Misha

Here is my version of Mattrssolution in Swift for injecting all cookies from HTTPCookieStorage. This was done mainly to inject an authentication cookie to create a user session.

这是我在 Swift 中的Mattrs解决方案版本,用于从 HTTPCookieStorage 注入所有 cookie。这样做主要是为了注入身份验证 cookie 以创建用户会话。

public func setupWebView() {
    let userContentController = WKUserContentController()
    if let cookies = HTTPCookieStorage.shared.cookies {
        let script = getJSCookiesString(for: cookies)
        let cookieScript = WKUserScript(source: script, injectionTime: .atDocumentStart, forMainFrameOnly: false)
        userContentController.addUserScript(cookieScript)
    }
    let webViewConfig = WKWebViewConfiguration()
    webViewConfig.userContentController = userContentController

    self.webView = WKWebView(frame: self.webViewContainer.bounds, configuration: webViewConfig)
}

///Generates script to create given cookies
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 {
        result += "document.cookie='\(cookie.name)=\(cookie.value); domain=\(cookie.domain); path=\(cookie.path); "
        if let date = cookie.expiresDate {
            result += "expires=\(dateFormatter.stringFromDate(date)); "
        }
        if (cookie.secure) {
            result += "secure; "
        }
        result += "'; "
    }
    return result
}

回答by cycDroid

set cookie

设置饼干

self.webView.evaluateJavaScript("document.cookie='access_token=your token';domain='your domain';") { (data, error) -> Void in
        self.webView.reload()
}

delete cookie

删除cookie

self.webView.evaluateJavaScript("document.cookie='access_token=';domain='your domain';") { (data, error) -> Void in
        self.webView.reload()
}

回答by Deep Parekh

Swift 3 update :

斯威夫特 3 更新:

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
    if let urlResponse = navigationResponse.response as? HTTPURLResponse,
       let url = urlResponse.url,
       let allHeaderFields = urlResponse.allHeaderFields as? [String : String] {
       let cookies = HTTPCookie.cookies(withResponseHeaderFields: allHeaderFields, for: url)
       HTTPCookieStorage.shared.setCookies(cookies , for: urlResponse.url!, mainDocumentURL: nil)
       decisionHandler(.allow)
    }
}

回答by Hymany

In iOS 11, you can manage cookie now :), see this session: https://developer.apple.com/videos/play/wwdc2017/220/

在 iOS 11 中,您现在可以管理 cookie :),请参阅此会话:https: //developer.apple.com/videos/play/wwdc2017/220/

enter image description here

在此处输入图片说明

回答by Dan Loewenherz

After looking through various answers here and not having any success, I combed through the WebKit documentation and stumbled upon the requestHeaderFieldsstatic method on HTTPCookie, which converts an array of cookies into a format suitable for a header field. Combining this with mattr's insightof updating the URLRequestbefore loading it with the cookie headers got me through the finish line.

在查看了这里的各种答案并且没有任何成功之后,我梳理了 WebKit 文档并偶然发现了 上的requestHeaderFields静态方法HTTPCookie,该方法将 cookie 数组转换为适合标题字段的格式。将此与mattrURLRequest在加载 cookie 标头之前更新它的洞察力相结合,使我通过了终点线。

Swift 4.1, 4.2, 5.0:

斯威夫特 4.1、4.2、5.0:

var request = URLRequest(url: URL(string: "https://example.com/")!)
let headers = HTTPCookie.requestHeaderFields(with: cookies)
for (name, value) in headers {
    request.addValue(value, forHTTPHeaderField: name)
}

let webView = WKWebView(frame: self.view.frame)
webView.load(request)

To make this even simpler, use an extension:

为了使这更简单,请使用扩展名:

extension WKWebView {
    func load(_ request: URLRequest, with cookies: [HTTPCookie]) {
        var request = request
        let headers = HTTPCookie.requestHeaderFields(with: cookies)
        for (name, value) in headers {
            request.addValue(value, forHTTPHeaderField: name)
        }

        load(request)
    }
}

Now it just becomes:

现在它变成了:

let request = URLRequest(url: URL(string: "https://example.com/")!)
let webView = WKWebView(frame: self.view.frame)
webView.load(request, with: cookies)

This extension is also available in LionheartExtensionsif you just want a drop-in solution. Cheers!

如果您只想要一个简单的解决方案,这个扩展也可以在LionheartExtensions中使用。干杯!

回答by Shauket Sheikh

The reason behind posted this answer is I tried many solution but no one work properly, most of the answer not work in case where have to set cookie first time, and got result cookie not sync first time, Please use this solution it work for both iOS >= 11.0 <= iOS 11 till 8.0, also work with cookie sync first time.

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

For iOS >= 11.0-- Swift 4.2

对于 iOS >= 11.0-- Swift 4.2

Get http cookiesand set in wkwebviewcookie store like this way, it's very tricky point to load your request in wkwebview, must sent request for loading when cookies gonna be set completely, here is function that i wrote.

获取的HTTP cookies和集wkwebviewcookie存储这样的方式,这是非常棘手的点加载在您的要求wkwebview,必须发送装载请求时会被完全设置cookies,这里是函数,我写的。

Call function with closurein completion you call load webview. FYI this function only handle iOS >= 11.0

在完成时调用带有闭包的函数,您调用 load webview。仅供参考此功能仅处理 iOS >= 11.0

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

Here is implementation for syncCookiesfunction.

这是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()
}
}

For iOS 8 till iOS 11

适用于 iOS 8 至 iOS 11

you need to setup some extra things you need to set two time cookies one through using WKUserScriptand dont forget to add cookies in request as well, otherwise your cookie not sync first time and you will see you page not load first time properly. this is the heck that i found to support cookies for iOS 8.0

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

before you Wkwebview object creation.

在您创建 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))


}

Focus on this function getJSCookiesString

重点关注这个函数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
}

Here is other step wkuserscript not sync cookies immediately, there a lot of heck to load first time page with cookie one is to reload webview again if it terminate process but i don't recommend to use it, its not good for user point of view, heck is whenever you ready to load request set cookies in request header as well like this way, don't forget to add iOS version check. before load request call this function.

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

request?.addCookies()

i wrote extension for URLRequest

我为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

        }
    }

  }
}

now you ready to go for testing iOS > 8

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