क्या मैं WKWebView द्वारा उपयोग की जाने वाली कुकीज़ सेट कर सकता हूं?


135

मैं से किसी मौजूदा ऐप स्विच करने के लिए कोशिश कर रहा हूँ UIWebViewकरने के लिए WKWebView। वर्तमान ऐप उपयोगकर्ताओं के लॉगिन / सत्र को प्रबंधित करता है webviewऔर cookiesमें प्रमाणीकरण के लिए आवश्यक सेट करता है NSHTTPCookieStore। दुर्भाग्य से नए का WKWebViewउपयोग नहीं करता cookiesहै NSHTTPCookieStorage। क्या इसे प्राप्त करने का एक और तरीका है?

जवाबों:


186

केवल 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 और उससे नीचे के पुराने उत्तर

यदि आपको अपने कुकीज़ को प्रारंभिक लोड अनुरोध पर सेट करने की आवश्यकता है, तो आप उन्हें NSMutableURLRequest पर सेट कर सकते हैं। क्योंकि कुकीज केवल एक विशेष रूप से प्रारूपित अनुरोध शीर्षलेख हैं जो इसे प्राप्त किया जा सकता है:

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 के अनुरोधों की आवश्यकता होती है कि उनकी कुकीज़ सेट हों, तो इसे WKUserScript का उपयोग करके प्राप्त किया जा सकता है ताकि दस्तावेज़ शुरू में जावास्क्रिप्ट के माध्यम से प्रोग्राम को मानों को निर्धारित किया जा सके:

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

इन दोनों तकनीकों के संयोजन से आपको नेटिव ऐप लैंड से वेब व्यू लैंड में कुकी मान स्थानांतरित करने के लिए पर्याप्त उपकरण मिलेंगे। अगर आपको कुछ और उन्नत कुकीज़ की आवश्यकता है, तो आप मोज़िला के पेज पर कुकी जावास्क्रिप्ट एपीआई पर अधिक जानकारी पा सकते हैं ।

हाँ, यह बेकार है कि Apple UIWebView की कई बारीकियों का समर्थन नहीं कर रहा है । यकीन नहीं होता कि वे कभी उनका समर्थन करेंगे, लेकिन उम्मीद है कि वे जल्द ही इस पर काम करेंगे। उम्मीद है की यह मदद करेगा!


1
बाद के अनुरोधों के लिए कुकीज़ इंजेक्ट करने के लिए सबसे अच्छी जगह कहाँ है? उदा। प्रारंभिक पृष्ठ लोड ऊपर दिए गए उत्तर में कवर किया गया है, लेकिन क्या होगा यदि उस पृष्ठ पर लिंक हैं जो उसी डोमेन पर भी जाते हैं, और अनुरोध में इंजेक्ट किए गए समान कुकीज़ की भी आवश्यकता है? didStartProvisionalNavigation?
मेसन जी। झ्विती

1
क्षमा करें, यह आपके लिए काम नहीं कर रहा है। मेरे दिमाग में, जब तक डोमेन समान हैं तब तक कोई समस्या नहीं होनी चाहिए। क्या आप उस कोड में दोबारा जांच कर सकते हैं कि लिंक उसी डोमेन की ओर इशारा कर रहा है जिससे आपने अनुरोध लोड किया था? इसके अलावा, कुकीज़ को एक विशिष्ट "पथ" के लिए भी विवश किया जा सकता है। शायद यह कुछ मुद्दों का कारण बन रहा है?
मेटर

11
ध्यान दें कि कुकीज़ सेट करने के लिए जावास्क्रिप्ट तकनीक "HTTP केवल" कुकीज़ के लिए काम नहीं करेगी।
अहमद नासिर

1
उपरोक्त विधि महान काम करती है ... लेकिन मैं बाद में AJAX कॉल (केवल एक बार डुप्लिकेट) में डुप्लिकेट कुकीज़ देख सकता था।
दुर्गा वुंडवल्ली

1
@ Axel92Dev एक वर्कअराउंड यह सुनिश्चित करने के लिए होगा कि आपके सर्वर से आपके वेबव्यू में किया गया पहला अनुरोध एक प्रतिक्रिया हो जो स्पष्ट रूप से वेबवॉच को HTTPOnly ध्वज के साथ कुकीज़ को फिर से सेट करने के लिए कहता है (यानी: प्रतिक्रिया में फिर से कुकीज़ सेट करें)। आप उस एकमात्र उद्देश्य के लिए एक विशेष एपीआई बना सकते हैं जब वेबवार्ता को आरम्भ किया जाता है, फिर सफलता पर सामान्य रूप से वेबव्यू का उपयोग करें।
अहमद नासिर

64

इस उत्तर के साथ खेलने के बाद (जो कल्पनात्मक रूप से उपयोगी था :) हमें कुछ बदलाव करने पड़े हैं:

  • हमें उन डोमेन के बीच निजी कुकी जानकारी को लीक किए बिना कई डोमेन से निपटने के लिए वेब दृश्यों की आवश्यकता है
  • हमें सुरक्षित कुकीज का सम्मान करने की आवश्यकता है
  • यदि सर्वर एक कुकी मान को बदल देता है, तो हम चाहते हैं कि हमारा ऐप इसके बारे में जानें NSHTTPCookieStorage
  • यदि सर्वर एक कुकी मान को बदल देता है, तो हम नहीं चाहते हैं कि जब हम लिंक / AJAX इत्यादि का पालन करें तो हमारी स्क्रिप्ट इसे फिर से इसके मूल मूल्य पर रीसेट कर दें।

इसलिए हमने अपने कोड को संशोधित किया;

एक अनुरोध बनाना

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

यह सुनिश्चित करता है कि पहले अनुरोध में सही कुकीज सेट है, बिना किसी कुकीज को साझा किए हुए स्टोरेज से जो अन्य डोमेन के लिए हैं, और बिना किसी सुरक्षित कुकीज़ को असुरक्षित अनुरोध में भेजे।

आगे के अनुरोधों से निपटना

हमें यह भी सुनिश्चित करने की आवश्यकता है कि अन्य अनुरोधों में कुकीज़ सेट हैं। यह एक स्क्रिप्ट का उपयोग करके किया जाता है जो दस्तावेज़ लोड पर चलता है जो यह देखने के लिए जांचता है कि क्या कोई कुकी सेट है और यदि नहीं, तो इसे मान में सेट करें 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];

कुकी परिवर्तनों से निपटना

हमें कुकी के मूल्य को बदलने वाले सर्वर से भी निपटने की आवश्यकता है। इसका मतलब यह है कि जिस वेब दृश्य को हम अपडेट करने के लिए बना रहे हैं, उसे वापस कॉल करने के लिए एक और स्क्रिप्ट जोड़ सकते हैं 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"];

और किसी भी कुकीज़ को बदलने के लिए प्रतिनिधि विधि को लागू करना, यह सुनिश्चित करना कि हम केवल वर्तमान डोमेन से कुकीज़ अपडेट कर रहे हैं!

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

यह हमारे कुकी समस्याओं को ठीक किए बिना लगता है कि हम प्रत्येक जगह से अलग-अलग तरीके से WKWebView का उपयोग करते हैं। अब हम इस कोड का उपयोग अपने वेब विचारों को बनाने के लिए सहायक के रूप में कर सकते हैं और यह NSHTTPCookieStorageहमारे लिए पारदर्शी रूप से अपडेट होता है।


संपादित करें: मैं 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;
}

6
मैंने आपका कोड WKWebView के उपवर्ग में लपेट दिया है। बेझिझक इसे बाहर की जाँच करने के लिए github.com/haifengkao/YWebView
Hai Feng Kao

क्या होगा अगर आपके कुकीज़ मूल्य में = संकेत हैं? क्या यह काम करेगा?
iOS26

@iOSAddicted मुझे ऐसा लगता है। यदि आपका मूल्य था a=bतो आप कुकी स्ट्रिंग के साथ समाप्त हो जाएंगे name=a=b;domain=.example.com;path=/- मेरा मानना ​​है कि मानक विभाजित होता है ;और फिर कुंजी = मूल्य जोड़ी में पहले पर विभाजित होता है =। मैं इसका परीक्षण करूंगा हालांकि :)
deanWombourne

आपकी प्रतिक्रिया से मुझे बहुत मदद मिली, फिर भी मैं आपके पोस्ट में कुछ जोड़ना चाहूंगा, आपकी अपडेट पद्धति का उपयोग करते समय कई जोखिम हैं, कुछ JS चौखटे कुकीज़ का निर्माण कर सकते हैं जिनका एक ही नाम है, लेकिन अलग-अलग डोमेन, और यदि आप इसे अपडेट करने का प्रयास करते हैं जेएस विधियों का उपयोग करने से आपको कुकी को गलत मान से अपडेट करने का उच्च जोखिम होता है। हमारे लिए भी js कुकी स्ट्रिंग को, उसके सुरक्षित झंडे को उतारना पड़ा, क्योंकि हमारा सर्वर http और https के बीच बुरा रीडायरेक्ट बनाता है, जिससे सुरक्षित कुकीज़ कुछ गंदा किनारे मामलों में कुछ पृष्ठों में मौजूद नहीं होती हैं।
रिकार्डो डुटार्टे

मुझे वास्तव में लगता है कि मैं जिस कंपनी के साथ था, मैंने लिखा था कि इसे लाइव करने के बाद इसमें कुछ डोमेन सुरक्षा को जोड़ना होगा। हम कभी नहीं (afaik) सुरक्षित / असुरक्षित समस्या में भाग गए - एक बुरा सपना लगता है!
deanWombourne

42

कुकीज़ को WKWebViewबनाए जाने से पहले कॉन्फ़िगरेशन पर सेट किया जाना चाहिए । अन्यथा, भले साथ WKHTTPCookieStoreके setCookieपूरा होने के हैंडलर, कुकीज़ मज़बूती से वेब दृश्य को समन्वयित नहीं किया जाएगा। इस से इस लाइन को वापस चला जाता डॉक्स परWKWebViewConfiguration

@NSCopying var configuration: WKWebViewConfiguration { get }

वह @NSCopyingकुछ गहरी नकल है। कार्यान्वयन मेरे से परे है, लेकिन अंतिम परिणाम यह है कि जब तक आप वेबव्यू को शुरू करने से पहले कुकीज़ सेट नहीं करते हैं, आप कुकीज़ के वहां होने पर भरोसा नहीं कर सकते। यह ऐप आर्किटेक्चर को जटिल कर सकता है क्योंकि किसी दृश्य को प्रारंभ करना एक अतुल्यकालिक प्रक्रिया बन जाती है। आप कुछ इस तरह से समाप्त करेंगे

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

और फिर इसे कुछ इस तरह उपयोग करने के लिए

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

उपरोक्त उदाहरण अंतिम संभावित क्षण तक निर्माण को देखते हैं, एक अन्य समाधान यह होगा कि पहले से कॉन्फ़िगरेशन या वेबव्यू को अच्छी तरह से बनाया जाए और व्यू कंट्रोलर के निर्माण से पहले अतुल्यकालिक प्रकृति को हैंडल किया जाए।

एक अंतिम नोट: एक बार जब आप इस वेबव्यू को बनाते हैं, तो आपने इसे जंगली में ढीला कर दिया है, आप इस उत्तर में वर्णित विधियों का उपयोग किए बिना अधिक कुकीज़ नहीं जोड़ सकते । हालाँकि आप WKHTTPCookieStoreObserverकुकी में हो रहे कम से कम परिवर्तनों का निरीक्षण करने के लिए एपीआई का उपयोग कर सकते हैं। तो अगर एक सत्र कुकी वेबव्यू में अपडेट हो जाती है, तो आप सिस्टम के मैन्युअल रूप से अपडेट कर सकते हैंHTTPCookieStorage चाहें तो इस नई कुकी साथ ।

इस पर अधिक जानकारी के लिए, इस 2017 WWDC सत्र कस्टम वेब सामग्री लोड हो रहा है पर 18:00 पर जाएं । इस सत्र की शुरुआत में, एक भ्रामक कोड नमूना है जो इस तथ्य को छोड़ देता है कि पूरा होने वाले हैंडलर में वेबव्यू बनाया जाना चाहिए।

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

18:00 पर लाइव डेमो यह स्पष्ट करता है।

Mojave Beta 7 और iOS 12 Beta 7 को कम से कम संपादित करें , मैं कुकीज़ के साथ अधिक सुसंगत व्यवहार देख रहा हूं। setCookie(_:)विधि के बाद भी सेटिंग कुकी को अनुमति देना दिखाई देता है WKWebViewबनाया गया है। मैं करने के लिए यह महत्वपूर्ण है, हालांकि लगता है, किया छू नहींprocessPool सब पर चर। कुकी सेटिंग कार्यक्षमता सबसे अच्छा तब काम करती है जब कोई अतिरिक्त पूल नहीं बनाया जाता है और जब वह संपत्ति अकेले अच्छी तरह से छोड़ दी जाती है। मुझे लगता है कि यह कहना सुरक्षित है कि हम WebKit में कुछ बग के कारण समस्याएँ थे।


लगता है कि कुकी हैंडलिंग / सेटिंग Mojave 10.14 बीटा 3 और iOS 12 बीटा 3 में अधिक विश्वसनीय है
nteissler

6
बहुत गहराई से और जवाब में
निकोलस कैरास्को

1
मैं अभी भी iOS 12 में पहले से लोड WKWebView के साथ इस मुद्दे को ले रहा हूं। कभी-कभी सेटकैकी () वास्तव में तुरंत WKWebView के साथ समन्वयित हो जाएगा, कभी-कभी यह हैंडलिंग को कुछ छिटपुट नहीं करेगा
bmjohns

मैंने अभी भी मुद्दों को देखा है क्योंकि रडार का दावा किया गया था, लेकिन बहुत कम बार। आप कितनी बार कुकी की विफलता देख रहे हैं? यदि आपके पास एक प्रतिलिपि प्रस्तुत करने योग्य, छोटा सा पर्याप्त प्रोजेक्ट है, तो मैं वास्तव में यहां एक वेबकिट बग प्रस्तुत करने की सलाह दूंगा : webkit.org/reporting-bugs आप सेब में ब्रैडी ईडसन (अच्छी तरह से) एक वेबकिट वास्तुकार को भी ट्वीट कर सकते हैं जो इन प्रकार के लिए बहुत संवेदनशील है। रिपोर्ट और कीड़े।
नेटीसलर

यह सही उत्तर है - प्रत्येक URLRequest में हेडर फ़ील्ड्स के रूप में कुकीज़ को मैन्युअल रूप से अनुवाद करने की कोई आवश्यकता नहीं है, यह बस है कि setCookie () को यहां वर्णित के रूप में उपयोग करने की आवश्यकता है।
गिलाउम लॉरेंट

25

मेरे लिए काम

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

विस्मयकारी हैक, विशेष रूप से कैसे एक मौजूदा WKWebView में कुकी को ओवरराइड करने के बारे में iOS कितना असहनीय है। एकमात्र गोचा यह है कि पिछले WKNavigationKey बासी हो गया है। अन्य कोड पुराने पर व्यर्थ की प्रतीक्षा कर सकते हैं।
बेसजेन

2
क्या ये सही है? सराहना करें यह कुछ परिस्थितियों में काम कर सकता है। हालाँकि इस प्रतिनिधि पद्धति की जिम्मेदारी - निर्णयपॉलिसीफोरनैविएशनएक्शन - पॉलिसी तय करना है; वास्तव में अनुरोध को लोड करने के लिए नहीं। जो कि पहले शुरू किया गया है। किस मामले में, यह अनुरोध दो बार लोड होने का कारण नहीं बनता है?
मैक्स मैकलेओड

2
@MaxMacLeod इस elseस्थिति में वह वास्तव में प्रारंभिक अनुरोध को लोड नहीं करता है, इसलिए वह decisionHandlerबंद करने को बुला रहा है । इस स्थिति में कॉल करने के बाद इस प्रतिनिधि विधि को उस अनुरोध के लिए फिर से बुलाया जाएगा और यह इस स्थिति में जाएगी क्योंकि हेडर मौजूद होगा। .cancelwebviewloadRequestelseifCookie
halil_g

2
हालांकि यह काम नहीं करेगा जब प्रारंभिक अनुरोध में पहले से ही कुछ कुकीज़ सेट हैं, क्योंकि यह कभी भी elseस्थिति में नहीं जाएगा ।
halil_g

ध्यान दें कि यह 1 है) हर स्थिति के लिए काम नहीं करता है - उदाहरण के लिए, मामला जब वेब दृश्य 2 फ्रेम लोड करता है) सुरक्षित नहीं है - यह संवेदनशील जानकारी के साथ कुकी को 3 पार्टी URL पर भेज सकता है
पीटर प्रोकॉप

20

यहाँ HTTPCookieStorage से सभी कुकीज़ इंजेक्षन के लिए स्विफ्ट में मैटर्स समाधान का मेरा संस्करण है । यह मुख्य रूप से उपयोगकर्ता सत्र बनाने के लिए एक प्रमाणीकरण कुकी को इंजेक्ट करने के लिए किया गया था।

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
}

स्थानीय स्वरूपण सही है यह सुनिश्चित करने के लिए इस लाइन को जोड़ने के लिए बेहतर है:dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
बुबुक्स

इसे कहाँ पर कॉल करें?
मार्कहॉक

यह स्विफ्ट 4 (मामूली समायोजन के साथ) में मेरे लिए ठीक काम किया
Frédéric Adda

यह मेरे लिए बहुत अच्छा काम करता है, लेकिन केवल दूसरी बार जब मैं साइट पर जाता हूं (पहली बार कुकीज़ सेट नहीं होती हैं) - कोई भी इस पार आता है?
MrChrisBarker

पहला भार दूसरी भार काम में त्रुटि देता है :( क्या समस्या हो सकती है?
शौकत शेख

10

कुकी सेट करें

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

कुकी हटाएं

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

9

स्विफ्ट 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)
    }
}

1
नमस्ते, क्या आप कुकीज़ को पाने के लिए भी कोड जोड़ सकते हैं HTTPCookieStorage.shared?
मार्क 12'17

यह एकमात्र तरीका है जो मैंने WKWebView को वेबव्यू द्वारा किए गए हर अनुरोध के लिए कुकीज़ को जोड़ने के लिए मिला है
Chicowitz

यदि इसमें प्रतिक्रिया में httponly कुकी शामिल है, तो आप इस तरह कुकीज़ मूल्य प्राप्त नहीं कर सकते।
ब्रेन

1
यह केवल कुकीज़ को httpcookies के स्टोरेज पर वापस सेट कर रहा है, कोड कहाँ है जो wkwebview के लिए कुकीज़ सेटअप करता है?
शौकत शेख

8

यहाँ विभिन्न उत्तरों को देखने और कोई सफलता नहीं मिलने के बाद, मैंने WebKit प्रलेखन के माध्यम से कंघी की और requestHeaderFieldsस्थैतिक विधि पर ठोकर खाई HTTPCookie, जो कि एक शीर्ष लेख फ़ील्ड के लिए उपयुक्त प्रारूप में कुकीज़ की एक सरणी को परिवर्तित करता है। इसे कुकी हेडर के साथ लोड करने से पहले अपडेट करने की मैटर की अंतर्दृष्टि के साथ इसे मिलाकर URLRequestमुझे फिनिश लाइन के माध्यम से मिला।

स्विफ्ट 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)

इसे और भी सरल बनाने के लिए, एक एक्सटेंशन का उपयोग करें:

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

अब यह बस बन जाता है:

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

यह एक्सटेंशन लायनहार्टटेक्स्टेंशन में भी उपलब्ध है यदि आप केवल ड्रॉप-इन समाधान चाहते हैं। चीयर्स!


1
@ShauketSheikh हम्म, किन स्थितियों में यह काम नहीं करता है?
डैन लोवेनहेर्ज़

मैं सिम्युलेटर 8 का उपयोग कर परीक्षण किया है कि यह कुकीज़ नहीं भेज रहा है। मैंने इसकी दोहरी जाँच की है।
शौकत शेख

मैंने अपना उत्तर पोस्ट किया आप @Dan
Shauket Sheikh

7

IOS 11 में, आप अभी कुकी प्रबंधित कर सकते हैं :), इस सत्र को देखें: https://developer.apple.com/videos/play/wwdc2017/220/

यहाँ छवि विवरण दर्ज करें


2
@ शोभाकर तिवारी क्यों? iOS11 औपचारिक रिलीज में क्या कोई बदलाव होता है?
जैकी

यदि आप केवल iOS 11 और ऊपर का समर्थन करते हैं तो जाने का सबसे अच्छा तरीका, यदि आपको पिछले संस्करणों का समर्थन करने की आवश्यकता है, तो पृष्ठ लोड करने से पहले जावास्क्रिप्ट का उपयोग करें।
पाशाण

यह मेरे लिए काम करता है, इस तथ्य को छोड़कर कि कभी-कभी सेटकुकी विधि DOESN'T अपने पूर्ण हैंडलर को नहीं चलाती है, जिसका अर्थ है कि कभी-कभी मेरा वेब पेज लोड नहीं होता है - केवल डिवाइस पर होता है, तीसरा / 4th / 5th समय समापन और फिर से खोलना होता है। वेबव्यू, और एक बार ऐसा होने के बाद, यह तब तक होता रहता है जब तक मैं ऐप को रीसेट नहीं कर देता - कोई भी इसमें चला जाता है?
बिन्या कोजेट

5

इस उत्तर को पोस्ट करने के पीछे कारण है कि मैंने कई समाधान की कोशिश की, लेकिन कोई भी ठीक से काम नहीं करता है, अधिकांश उत्तर उस स्थिति में काम नहीं करते हैं जहां पहली बार कुकी सेट करनी है, और परिणाम कुकी पहली बार सिंक नहीं हुई है, कृपया इस समाधान का उपयोग करें दोनों के लिए काम करें iOS> = 11.0 <= iOS 11 8.0 तक, पहली बार कुकी सिंक के साथ भी काम करें।

IOS के लिए = = 11.0 - स्विफ्ट 4.2

Http कुकीज़ प्राप्त करें और wkwebview कुकी स्टोर में इस तरह से सेट करें, यह wwwebview में आपके अनुरोध को लोड करने के लिए बहुत ही मुश्किल बिंदु है , जरूरी लोड करने के लिए अनुरोध भेजा जब कुकीज़ पूरी तरह से सेट किया जा वाला, यहाँ समारोह है कि मैं लिखा था।

आप लोड वेबव्यू को पूरा करने में बंद होने के साथ कॉल फ़ंक्शन । FYI करें यह फ़ंक्शन केवल 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 का उपयोग करके दो बार कुकीज़ सेट करने की आवश्यकता है और साथ ही अनुरोध में कुकीज़ जोड़ना न भूलें, अन्यथा आपकी कुकी पहली बार सिंक नहीं होती है और आप देखेंगे कि आप पृष्ठ को पहली बार ठीक से लोड नहीं कर रहे हैं। यह वह बिल्ली है जिसे मैंने iOS 8.0 के लिए कुकीज़ का समर्थन करने के लिए पाया था

इससे पहले कि आप 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 है जो तुरंत कुकीज़ को सिंक नहीं करते हैं, कुकी के साथ पहली बार पृष्ठ लोड करने के लिए बहुत सारी बिल्ली है, अगर यह प्रक्रिया समाप्त हो जाती है तो फिर से वेबव्यू फिर से लोड करना है लेकिन मैं इसका उपयोग करने की सलाह नहीं देता, यह उपयोगकर्ता की दृष्टि से अच्छा नहीं है , बिल्ली जब भी आप अनुरोध शीर्षक में अनुरोध सेट कुकीज़ को लोड करने के लिए तैयार हैं, तो इस तरह से आईओएस संस्करण की जांच को जोड़ना न भूलें। लोड अनुरोध से पहले इस फ़ंक्शन को कॉल करें।

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 का परीक्षण करने के लिए तैयार हैं


2

कृपया वह समाधान खोजें, जो आपके लिए बॉक्स से बाहर होने की सबसे अधिक संभावना है। मूल रूप से यह स्विफ्ट 4 @ user3589213 के उत्तर के लिए संशोधित और अद्यतन है ।

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

1

मैंने उपरोक्त सभी उत्तरों की कोशिश की है, लेकिन उनमें से कोई भी काम नहीं करता है। इतने प्रयासों के बाद आखिरकार मुझे WKWebview कुकी सेट करने का एक विश्वसनीय तरीका मिल गया है।

सबसे पहले आपको WKProcessPool का एक उदाहरण बनाना होगा और इसे WKWebViewConfiguration पर सेट करना होगा जिसका उपयोग खुद WkWebview को शुरू करने के लिए किया जाना है:

    private lazy var mainWebView: WKWebView = {
        let webConfiguration = WKWebViewConfiguration()
        webConfiguration.processPool = WKProcessPool()
        let webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.navigationDelegate = self
        return webView
    }()

WKProcessPool को सेट करना यहां सबसे महत्वपूर्ण कदम है। WKWebview प्रक्रिया अलगाव का उपयोग करता है - जिसका अर्थ है कि यह आपके ऐप की प्रक्रिया से अलग प्रक्रिया पर चलता है। यह कभी-कभी संघर्ष का कारण बन सकता है और आपके कुकी को WKWebview के साथ ठीक से सिंक होने से रोक सकता है।

अब WKProcessPool की परिभाषा देखें

वेब दृश्य के साथ संबद्ध प्रक्रिया पूल इसके वेब दृश्य कॉन्फ़िगरेशन द्वारा निर्दिष्ट किया जाता है। कार्यान्वयन-परिभाषित प्रक्रिया की सीमा पूरी होने तक प्रत्येक वेब दृश्य को अपनी वेब सामग्री प्रक्रिया दी जाती है; उसके बाद, उसी प्रक्रिया पूल के साथ वेब दृश्य वेब सामग्री प्रक्रियाओं को साझा करते हुए समाप्त होते हैं।

अंतिम वाक्य पर ध्यान दें यदि आप बाद के अनुरोधों के लिए उसी WKWebview का उपयोग करने की योजना बनाते हैं

एक ही प्रक्रिया पूल के साथ वेब दृश्य वेब सामग्री प्रक्रियाओं को साझा करने के अंत में

मेरे कहने का अर्थ यह है कि यदि आप WKProcessPool के एक ही उदाहरण का उपयोग नहीं करते हैं तो हर बार जब आप एक ही डोमेन के लिए WKWebView को कॉन्फ़िगर करते हैं (हो सकता है कि आपके पास VC A हो जिसमें WKWebView शामिल हो और आप विभिन्न स्थानों में VC A के विभिन्न उदाहरण बनाना चाहते हैं ), वहाँ संघर्ष सेटिंग कुकीज़ हो सकता है। समस्या को हल करने के लिए, WKProcessPool के लिए WKWebView की पहली रचना के बाद, जो कि डोमेन B को लोड करता है, मैं इसे एक सिंगलटन में सहेजता हूं और उसी WKProcessPool का उपयोग करने के लिए हर बार मुझे एक WKWcessView बनाता है जो उसी डोमेन B को लोड करता है

private lazy var mainWebView: WKWebView = {
    let webConfiguration = WKWebViewConfiguration()
    if Enviroment.shared.processPool == nil {
        Enviroment.shared.processPool = WKProcessPool()
    }
    webConfiguration.processPool = Enviroment.shared.processPool!
    webConfiguration.processPool = WKProcessPool()
    let webView = WKWebView(frame: .zero, configuration: webConfiguration)
    webView.navigationDelegate = self
    return webView
}()

आरंभीकरण प्रक्रिया के बाद, आप पूरा होने वाले ब्लॉक के अंदर URLRequest लोड कर सकते हैं httpCookieStore.setCookie। यहां, आपको कुकी को अनुरोध हेडर में संलग्न करना होगा अन्यथा यह काम नहीं करेगा।

P / s: मैंने डैन लोवेनहर्ज द्वारा ऊपर दिए गए शानदार जवाब से एक्सटेंशन चुरा लिया है

mainWebView.configuration.websiteDataStore.httpCookieStore.setCookie(your_cookie) {
        self.mainWebView.load(your_request, with: [your_cookie])
}

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

1

Nteiss के उत्तर का मेरा संस्करण। पर परीक्षण किया गया iOS 11, 12, 13। आप की तरह लग रहा उपयोग करने के लिए की जरूरत नहीं है DispatchGroupपरiOS 13 अब और।

मैं गैर स्थिर समारोह का उपयोग includeCustomCookiesपर WKWebViewConfiguration, ताकि मैं अद्यतन कर सकते हैं cookiesहर बार जब मैं नया बनाने के WKWebViewConfiguration

extension WKWebViewConfiguration {
    func includeCustomCookies(cookies: [HTTPCookie], completion: @escaping  () -> Void) {
        let dataStore = WKWebsiteDataStore.nonPersistent()
        let waitGroup = DispatchGroup()

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

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

फिर मैं इसे इस तरह उपयोग करता हूं:

let customUserAgent: String = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Safari/605.1.15"

let customCookies: [HTTPCookie] = {
    let cookie1 = HTTPCookie(properties: [
        .domain: "yourdomain.com",
        .path: "/",
        .name: "auth_token",
        .value: APIManager.authToken
    ])!

    let cookie2 = HTTPCookie(properties: [
        .domain: "yourdomain.com",
        .path: "/",
        .name: "i18next",
        .value: "ru"
    ])!

    return [cookie1, cookie2]
}()

override func viewDidLoad() {
    super.viewDidLoad()

    activityIndicatorView.startAnimating()

    let webConfiguration = WKWebViewConfiguration()
    webConfiguration.includeCustomCookies(cookies: customCookies, completion: { [weak self] in
        guard let strongSelf = self else { return }
        strongSelf.webView = WKWebView(frame: strongSelf.view.bounds, configuration: webConfiguration)
        strongSelf.webView.customUserAgent = strongSelf.customUserAgent
        strongSelf.webView.navigationDelegate = strongSelf
        strongSelf.webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        strongSelf.view.addSubview(strongSelf.webView)
        strongSelf.view.bringSubviewToFront(strongSelf.activityIndicatorView)
        strongSelf.webView.load(strongSelf.request)
    })
}

0

XHR अनुरोधों के लिए बेहतर सुधार यहां दिखाया गया है

स्विफ्ट 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

अगर कोई भी अल्मोफायर का उपयोग कर रहा है, तो यह बेहतर उपाय है।

  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

यह मेरे लिए काम करता है: सेटकुकीज़ के बाद, fetchdatarecords जोड़ें

   let cookiesSet = NetworkProvider.getCookies(forKey : 
    PaywallProvider.COOKIES_KEY, completionHandler: nil)
                let dispatchGroup = DispatchGroup()
                for (cookie) in cookiesSet {
                    if #available(iOS 11.0, *) {
                        dispatchGroup.enter()
                        self.webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie){
                            dispatchGroup.leave()
                            print ("cookie added: \(cookie.description)")
                            }
                        } else {
                                            // TODO Handle ios 10 Fallback on earlier versions
                        }
                    }
                    dispatchGroup.notify(queue: .main, execute: {


    self.webView.configuration.websiteDataStore.fetchDataRecords(ofTypes: 
    WKWebsiteDataStore.allWebsiteDataTypes()) { records in
                            records.forEach { record in

                                print("[WebCacheCleaner] Record \(record)")
                            }
                            self.webView.load(URLRequest(url: 
    self.dataController.premiumArticleURL , 
    cachePolicy:NSURLRequest.CachePolicy.reloadIgnoringLocalAndRemoteCacheData,
                                                         timeoutInterval: 10.0))
                        }

                    })
                }

0

जब गुणा कुकी आइटम जोड़ने, तो आप इसे इस तरह से कर सकते हैं: ( pathऔर domainप्रत्येक आइटम के लिए आवश्यकता होती है)

NSString *cookie = [NSString stringWithFormat:@"document.cookie = 'p1=%@;path=/;domain=your.domain;';document.cookie = 'p2=%@;path=/;domain=your.domain;';document.cookie = 'p3=%@;path=/;domain=your.domain;';", p1_string, p2_string, p3_string];

WKUserScript *cookieScript = [[WKUserScript alloc]
            initWithSource:cookie
            injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];

[userContentController addUserScript:cookieScript];

अन्यथा, केवल पहला कुकी आइटम सेट किया जाएगा।


0

आप UIWebView से HTTPCookieStorage के समान व्यवहार प्राप्त करने के लिए WKWebsiteDataStore का भी उपयोग कर सकते हैं।

let dataStore = WKWebsiteDataStore.default()
let cookies = HTTPCookieStorage.shared.cookies ?? [HTTPCookie]()
cookies.forEach({
    dataStore.httpCookieStore.setCookie($0, completionHandler: nil)
})

0

नीचे कोड मेरी परियोजना स्विफ्ट 5 में अच्छी तरह से काम कर रहा है। नीचे WKWebView द्वारा लोड url आज़माएं:

    private func loadURL(urlString: String) {
        let url = URL(string: urlString)
        guard let urlToLoad = url else { fatalError("Cannot find any URL") }

        // Cookies configuration
        var urlRequest = URLRequest(url: urlToLoad)
        if let cookies = HTTPCookieStorage.shared.cookies(for: urlToLoad) {
            let headers = HTTPCookie.requestHeaderFields(with: cookies)
            for header in headers { urlRequest.addValue(header.value, forHTTPHeaderField: header.key) }
        }

        webview.load(urlRequest)
    }

0

यह iOS 9 या बाद में कुकीज़ और WKWebView के साथ निपटने के लिए मेरा समाधान है।

import WebKit

extension WebView {

    enum LayoutMode {
        case fillContainer
    }

    func autoLayout(_ view: UIView?, mode: WebView.LayoutMode = .fillContainer) {
        guard let view = view else { return }
        self.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(self)

        switch mode {
        case .fillContainer:
                NSLayoutConstraint.activate([
                self.topAnchor.constraint(equalTo: view.topAnchor),
                self.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                self.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                self.bottomAnchor.constraint(equalTo: view.bottomAnchor)
            ])
        }
    }

}

class WebView : WKWebView {

    var request : URLRequest?

    func load(url: URL, useSharedCookies: Bool = false) {
        if useSharedCookies, let cookies = HTTPCookieStorage.shared.cookies(for: url) {
            self.load(url: url, withCookies: cookies)
        } else {
            self.load(URLRequest(url: url))
        }
    }

    func load(url: URL, withCookies cookies: [HTTPCookie]) {
        self.request = URLRequest(url: url)
        let headers = HTTPCookie.requestHeaderFields(with: cookies)
        self.request?.allHTTPHeaderFields = headers
        self.load(request!)
    }

}

0

यह गलती जो मैं कर रहा था वह यह है कि मैं पूरे URL को डोमेन विशेषता में पास कर रहा था, यह केवल डोमेन नाम होना चाहिए।

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

webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.