Czy Mogę ustawić pliki cookie, które będą używane przez WKWebView?

Próbuję przełączyć istniejącą aplikację z UIWebView na WKWebView. Obecna aplikacja zarządza logowaniem / sesją użytkowników poza widokiem sieciowym i ustawia pliki cookie wymagane do uwierzytelniania w sklepie NSHTTPCookieStore. Niestety Nowy WKWebView nie używa plików cookie z nshttpcookiestorage. Czy jest inny sposób, aby to osiągnąć?

Author: Col, 2014-10-26

13 answers

Edycja tylko dla iOS 11+

Użyj WKHTTCookieStore :

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

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

Ponieważ wyciągasz je z HTTPCookeStorage, możesz to zrobić:

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

Stara odpowiedź dla iOS 10 i poniżej

Jeśli chcesz, aby Twoje pliki cookie były ustawione na początkowym żądaniu ładowania, możesz ustawić je na NSMutableURLRequest. Ponieważ pliki cookie są tylko specjalnie sformatowanym nagłówkiem żądania, można to osiągnąć w następujący sposób:

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];

Jeśli potrzebujesz późniejszego AJAX żądania na stronie, aby mieć ustawione pliki cookie, można to osiągnąć po prostu za pomocą WKUserScript, aby ustawić wartości programowo za pomocą javascript na początku dokumentu w następujący sposób:

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];

Połączenie tych dwóch technik powinno zapewnić wystarczającą ilość narzędzi do przenoszenia wartości plików cookie z natywnego obszaru aplikacji do obszaru widoku sieci Web. Więcej informacji na temat cookie javascript api można znaleźć na stronie Mozilli, jeśli potrzebujesz bardziej zaawansowanych plików cookie.

Yeah it sucks that Apple is not obsługa wielu z Nicei UIWebView. Nie jestem pewien, czy kiedykolwiek ich wesprą, ale mam nadzieję, że wkrótce się tym zajmą. Mam nadzieję, że to pomoże!

 103
Author: mattr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-16 13:16:01

Po zabawie z ta odpowiedź (która była fantastycznie pomocna :) musieliśmy wprowadzić kilka zmian:

    Pliki cookies wykorzystywane są w celu świadczenia usług na najwyższym poziomie, w tym w celu świadczenia usług na najwyższym poziomie.]} Jest to niezbędne do przestrzegania bezpiecznych plików cookie.]}
  • jeśli serwer zmieni wartość pliku cookie, chcemy, aby nasza aplikacja wiedziała o tym w NSHTTPCookieStorage
  • jeśli serwer zmieni wartość pliku cookie, nie chcemy, aby nasze Skrypty zresetowały go z powrotem oryginalna wartość po kliknięciu linku / AJAX itp.

Więc zmodyfikowaliśmy nasz kod, aby był taki;

Tworzenie żądania

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...

Zapewnia to, że pierwsze żądanie ma ustawione prawidłowe pliki cookie, bez wysyłania żadnych plików cookie ze współdzielonej pamięci masowej, które są dla innych domen, i bez wysyłania żadnych bezpiecznych plików cookie do niezabezpieczonego żądania.

Rozpatrywanie kolejnych wniosków

Musimy również upewnić się, że inne żądania mają ustawione pliki cookie. To odbywa się za pomocą skryptu uruchamianego przy ładowaniu dokumentu, który sprawdza, czy istnieje plik cookie, a jeśli nie, ustaw go na wartość w 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];

Radzenie sobie ze zmianami plików cookie

Musimy również poradzić sobie z serwerem zmieniającym wartość pliku cookie. Oznacza to dodanie kolejnego skryptu do wywołania z widoku sieci, który tworzymy w celu aktualizacji naszej 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"];

I zaimplementowanie metody delegate, aby zaktualizować wszelkie zmienione pliki cookie, upewniając się, że że aktualizujemy tylko pliki cookie z bieżącej domeny!

- (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];
        }
    }
}

To wydaje się rozwiązywać nasze problemy z plikami cookie bez konieczności radzenia sobie z każdym miejscem, z którego korzystamy WKWebView inaczej. Możemy teraz użyć tego kodu jako pomocnika do tworzenia naszych webviewów i transparentnie aktualizuje NSHTTPCookieStorage dla nas.


EDIT: okazało się, że użyłem prywatnej kategorii na NSHTTPCookie - oto kod:

- (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;
}
 54
Author: deanWombourne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:37

Pracuj dla mnie

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)
    }
}
 19
Author: user3589213,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-25 05:58:58

Oto moja wersja Mattrs rozwiązania w języku Swift do wstrzykiwania wszystkich plików cookie z HTTPCookieStorage. Dokonano tego głównie po to, aby wstrzyknąć plik cookie uwierzytelniania w celu utworzenia sesji użytkownika.

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
}
 13
Author: Misha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-30 10:50:47

Pliki cookie muszą być ustawione w konfiguracji przed utworzeniem WKWebView. W przeciwnym razie, nawet po zakończeniu obsługi WKHTTPCookieStore, Pliki cookie nie zostaną niezawodnie zsynchronizowane z widokiem sieciowym. To wraca do tej linii z docs on WKWebViewConfiguration

@NSCopying var configuration: WKWebViewConfiguration { get }

To @NSCopying jest dość głęboką kopią. Implementacja jest poza mną, ale efekt końcowy jest taki, że jeśli nie ustawisz plików cookie przed zainicjowaniem widoku sieci Web, nie możesz liczyć na to, że pliki cookie tam będą. To może skomplikować architekturę aplikacji, ponieważ nie inicjalizacja widoku staje się procesem asynchronicznym. Skończysz z czymś takim

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)
        }
    }
}

A potem użyć czegoś w rodzaju

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

Powyższy przykład odkłada Tworzenie widoku do ostatniej możliwej chwili, innym rozwiązaniem byłoby utworzenie config lub webview z dużym wyprzedzeniem i obsługa asynchronicznego charakteru przed utworzeniem kontrolera widoku.

Ostatnia uwaga: Po utworzeniu tego webview, masz go ustawić nie możesz dodać więcej ciasteczek bez użycia metod opisanych w tej odpowiedzi. Możesz jednak użyć API WKHTTPCookieStoreObserver, aby przynajmniej obserwować zmiany zachodzące w plikach cookie. Jeśli więc plik cookie sesji zostanie zaktualizowany w widoku sieci Web, w razie potrzeby można ręcznie zaktualizować system HTTPCookieStorage za pomocą tego nowego pliku cookie.

Aby dowiedzieć się więcej na ten temat, przejdź do 18:00 w tym 2017 WWDC Session Custom web Content Loading. Na początku tej sesji znajduje się zwodnicza próbka kodu który pomija fakt, że webview powinien być utworzony w programie obsługi zakończenia.
cookieStore.setCookie(cookie!) {
    webView.load(loggedInURLRequest)
}

Demo na żywo o 18: 00 wyjaśnia to.

Edit przynajmniej od wersji Mojave Beta 7 i IOS 12 Beta 7 widzę znacznie bardziej spójne zachowanie z plikami cookie. Metoda setCookie(_:) wydaje się nawet zezwalać na ustawianie plików cookie po utworzeniu WKWebView. Uważam jednak, że ważne jest, aby w ogóle nie dotykać zmiennej processPool. Funkcjonalność ustawienia plików cookie działa najlepiej kiedy nie są tworzone żadne dodatkowe baseny i kiedy ta nieruchomość jest pozostawiona sama sobie. Myślę, że można bezpiecznie powiedzieć, że mieliśmy problemy z powodu pewnych błędów w WebKit.

 10
Author: nteiss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-20 20:25:23

Swift 3 update:

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)
    }
}
 8
Author: Deep Parekh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-21 18:11:17

Set cookie

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

Usuń plik cookie

self.webView.evaluateJavaScript("document.cookie='access_token=';domain='your domain';") { (data, error) -> Void in
        self.webView.reload()
}
 7
Author: cycDroid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-15 03:52:32

W iOS 11 możesz teraz zarządzać ciasteczkiem:), zobacz tę sesję: https://developer.apple.com/videos/play/wwdc2017/220/

Tutaj wpisz opis obrazka

 6
Author: Jacky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-22 05:31:33

Proszę znaleźć rozwiązanie, które najprawdopodobniej będzie działać dla ciebie po wyjęciu z pudełka. Zasadniczo jest to zmodyfikowane i zaktualizowane dla Swift 4 @ user3589213 ' S answer .

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    let headerKeys = navigationAction.request.allHTTPHeaderFields?.keys
    let hasCookies = headerKeys?.contains("Cookie") ?? false

    if hasCookies {
        decisionHandler(.allow)
    } else {
        let cookies = HTTPCookie.requestHeaderFields(with: HTTPCookieStorage.shared.cookies ?? [])

        var headers = navigationAction.request.allHTTPHeaderFields ?? [:]
        headers += cookies

        var req = navigationAction.request
        req.allHTTPHeaderFields = headers

        webView.load(req)

        decisionHandler(.cancel)
    }
}
 2
Author: Vadim Bulavin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-28 10:17:57

Po przejrzeniu różnych odpowiedzi tutaj i nie mając żadnego sukcesu, przejrzałem dokumentację WebKit i natknąłem się na requestHeaderFields statyczna metoda na HTTPCookie, która konwertuje tablicę plików cookie do formatu odpowiedniego dla pola nagłówka. Połączenie tego z wglądem mattra W aktualizację URLRequest przed załadowaniem go z nagłówkami ciasteczek pozwoliło mi przejść przez linię mety.

Swift 4.1:

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)

Aby to jeszcze uprościć, użyj rozszerzenie:

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)
    }
}

Teraz staje się:

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

To rozszerzenie jest również dostępne w LionheartExtensions , jeśli chcesz tylko dostać rozwiązanie typu drop-in. Zdrowie!

 1
Author: Dan Loewenherz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-30 20:26:57

Powodem zamieszczonej odpowiedzi jest to, że próbowałem wielu rozwiązań, ale nie działają poprawnie większość odpowiedzi nie działa po raz pierwszy, proszę użyć mojego rozwiązania działa zarówno dla iOS większego niż 11.0 i mniej niż iOS 11 do 8.0

Dla iOS >= 11.0 -- Swift 4.2

Get http cookies and set in wkwebview cookie store w ten sposób, to bardzo trudny punkt, aby załadować żądanie w wkwebview , musi wysłać żądanie do ładowania, gdy pliki cookie będą ustawione całkowicie, oto funkcja, którą napisałem.

Wywołanie funkcji zclosure W zakończeniu wywołujesz load webview. FYI ta funkcja obsługuje tylko iOS >= 11.0

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

Oto implementacja dlafunkcji 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()
}
}

Dla iOS 8 do iOS 11

Musisz skonfigurować kilka dodatkowych rzeczy, które musisz ustawić dwa pliki cookie raz za pomocą WKUserScript i nie zapomnij dodać plików cookie w żądaniu, jak również, w przeciwnym razie cookie nie Synchronizuj za pierwszym razem, a zobaczysz, że strona nie ładuje się poprawnie po raz pierwszy. to jest piekło, które znalazłem do obsługi plików cookie dla iOS 8.0

Przed utworzeniem obiektu 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

 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
}

Oto inny krok wkuserscript nie synchronizować plików cookie natychmiast, tam dużo heck, aby załadować stronę po raz pierwszy z ciasteczkiem jeden jest przeładować webview ponownie, jeśli zakończy proces, ale nie polecam go używać, to nie jest dobre dla użytkownika z punktu widzenia, heck jest zawsze, gdy jesteś gotowy do załadowania plików cookie ustawionych w nagłówku żądania, jak również w ten sposób, nie zapomnij dodać sprawdzania wersji iOS. przed załadowaniem żądania wywołaj tę funkcję.

request?.addCookies()

Napisałem rozszerzenie dla 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

        }
    }

  }
}

Teraz możesz przetestować iOS > 8

 1
Author: Shauket Sheikh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-26 03:26:21

Lepsza poprawka dla żądań XHR jest pokazana Tutaj

Wersja Swift 4:

func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Swift.Void) {
    guard
        let response = navigationResponse.response as? HTTPURLResponse,
        let url = navigationResponse.response.url
    else {
        decisionHandler(.cancel)
        return
    }

    if let headerFields = response.allHeaderFields as? [String: String] {
        let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url)
        cookies.forEach { (cookie) in
            HTTPCookieStorage.shared.setCookie(cookie)
        }
    }

    decisionHandler(.allow)
}
 0
Author: Lloyd Keijzer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-13 08:11:55

Jeśli ktoś używa Alamofire, to jest to lepsze rozwiązanie.

  let cookies = Alamofire.SessionManager.default.session.configuration.httpCookieStorage?.cookies(for: URL(string: BASE_URL)!)
  for (cookie) in cookies ?? [] {
      webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie)
  }
 0
Author: jeet.chanchawat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-04 13:35:46