Programming

WKWebView에서 사용할 쿠키를 설정할 수 있습니까?

procodes 2020. 8. 8. 14:09
반응형

WKWebView에서 사용할 쿠키를 설정할 수 있습니까?


기존 앱을에서 UIWebView전환하려고 합니다 WKWebView. 현재 응용 프로그램은 사용자 로그인 / 세션의 외부 관리 webview및 설정합니다 cookies하여로 인증에 필요한를 NSHTTPCookieStore. 불행하게도 새로운 WKWebView를 사용하지 않습니다 cookies로부터 NSHTTPCookieStorage. 이것을 달성하는 다른 방법이 있습니까?


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

이 두 기술을 결합하면 쿠키 값을 Native App Land에서 Web View Land로 전송할 수있는 충분한 도구가 제공됩니다. 좀 더 고급 쿠키가 필요한 경우 Mozilla 페이지 에서 쿠키 javascript API 에 대한 자세한 정보를 찾을 수 있습니다 .

예, Apple이 UIWebView의 많은 장점을 지원하지 않는다는 것은 짜증납니다 . 그들이 그들을 지원할 것인지는 확실하지 않지만, 곧이 일을 할 수 있기를 바랍니다. 도움이 되었기를 바랍니다!


이 답변 (환상적으로 도움 이 되었음)으로 재생 한 후 몇 가지 변경 사항을 적용해야했습니다.

  • 여러 도메인을 처리하려면 해당 도메인간에 개인 쿠키 정보를 유출하지 않고 웹보기가 필요합니다.
  • 보안 쿠키를 존중하기 위해 필요합니다.
  • 서버가 쿠키 값을 변경하면 앱이 쿠키 값을 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"];

변경된 쿠키를 업데이트하는 delegate 메서드를 구현하여 현재 도메인의 쿠키 만 업데이트하도록합니다!

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

쿠키를 만들기 전에 구성에 대해 설정해야합니다 WKWebView. 그렇지 않으면 WKHTTPCookieStoresetCookie완료 핸들러를 사용하더라도 쿠키가 웹보기에 안정적으로 동기화되지 않습니다. 이것은 문서 에서이 줄로 돌아갑니다 .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
    }
}

위의 예는 가능한 마지막 순간까지보기 생성을 연기합니다. 또 다른 해결책은 구성 또는 웹보기를 미리 생성하고보기 컨트롤러를 생성하기 전에 비동기 특성을 처리하는 것입니다.

마지막 참고 사항 :이 웹보기를 만들고 나면 야생으로 설정하면 이 답변에 설명 된 방법을 사용하지 않고 더 많은 쿠키를 추가 할 수 없습니다 . 그러나 WKHTTPCookieStoreObserverAPI를 사용하여 적어도 쿠키에 발생하는 변경 사항을 관찰 할 수 있습니다 . 따라서 웹보기에서 세션 쿠키가 업데이트 HTTPCookieStorage되면 원하는 경우이 새 쿠키로 시스템을 수동으로 업데이트 할 수 있습니다 .

이에 대한 자세한 내용은이 2017 WWDC 세션 사용자 지정 웹 콘텐츠로드 에서 18:00로 건너 뛰십시오 . 이 세션의 시작 부분에는 완료 핸들러에서 웹뷰를 생성해야한다는 사실을 생략 한기만 코드 샘플이 있습니다.

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

18:00의 라이브 데모에서이를 명확히합니다.

편집 적어도 모하비 베타 7, 아이폰 OS 12 베타 (7)로서, 나는 쿠키와 훨씬 더 일관된 동작을보고 있어요. setCookie(_:)방법 WKWebView은이 생성 된 후 쿠키 설정을 허용하는 것처럼 보입니다 . 내가하는 것이 중요하지만를 발견했다 만지지processPool 전혀 변수를. 쿠키 설정 기능은 추가 풀이 생성되지 않고 해당 속성이 그대로 유지 될 때 가장 잘 작동합니다. WebKit의 일부 버그로 인해 문제가 발생했다고 말하는 것이 안전하다고 생각합니다.


나를 위해 일해

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

다음은 HTTPCookieStorage 에서 모든 쿠키를 삽입하기위한 Swift Mattrs 솔루션 버전입니다 . 이것은 주로 사용자 세션을 생성하기 위해 인증 쿠키를 삽입하기 위해 수행되었습니다.

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
}

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

쿠키 설정

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

iOS 11에서는 지금 쿠키를 관리 할 수 ​​있습니다. :), 다음 세션을 참조하십시오 : https://developer.apple.com/videos/play/wwdc2017/220/

여기에 이미지 설명 입력


여기에서 다양한 답변을 살펴보고 성공하지 못한 후 WebKit 문서를 살펴본 후 쿠키 배열을 헤더 필드에 적합한 형식으로 변환하는 requestHeaderFields정적 메서드를 우연히 발견했습니다 HTTPCookie. 이것을 쿠키 헤더로로드하기 전에 업데이트에 대한 mattr의 통찰력 과 결합 URLRequest하여 결승선을 통과했습니다.

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

이 확장은 드롭 인 솔루션을 원하는 경우 LionheartExtensions 에서도 사용할 수 있습니다 . 건배!


이 답변을 게시 한 이유는 많은 솔루션을 시도했지만 아무도 제대로 작동하지 않습니다. 처음에 쿠키를 설정해야하고 결과 쿠키가 처음 동기화되지 않은 경우 대부분의 답변이 작동하지 않습니다.이 솔루션을 사용하십시오. iOS> = 11.0 <= iOS 11 ~ 8.0, 쿠키 동기화도 처음으로 작동합니다.

iOS> = 11.0의 경우 -Swift 4.2

가져 오기 HTTP 쿠키 와의 세트 wkwebview의 이 방법으로 같은 쿠키의 저장, 그것은 귀하의 요청을로드하는 매우 까다로운 점이다 wkwebview은 여기, 쿠키가 완전히 설정 될 거 할 때, 반드시로드에 대한 요청을 보낸 내가 쓴 기능입니다.

와 전화 기능 폐쇄 완료에 당신은 부하 웹뷰를 호출합니다. 참고로이 함수는 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가 쿠키를 즉시 동기화하지 않는 다른 단계입니다. 쿠키 1로 처음 페이지를로드하는 것은 프로세스를 종료하면 webview를 다시로드하는 것이지만 사용하지 않는 것이 좋습니다. 사용자 관점에는 좋지 않습니다. , 이런 식으로 요청 헤더에 요청 세트 쿠키를로드 할 준비가 될 때마다 iOS 버전 확인을 추가하는 것을 잊지 마십시오. 로드 요청 전에이 함수를 호출하십시오.

request?.addCookies()

URLRequest에 대한 확장을 작성했습니다.

extension URLRequest {

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

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

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

        }
    }

  }
}

이제 iOS> 8을 테스트 할 준비가되었습니다.


귀하에게 가장 적합한 솔루션을 즉시 찾으십시오. 기본적으로 Swift 4 @ user3589213답변에 대해 수정 및 업데이트되었습니다 .

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

위의 모든 답변을 시도했지만 아무것도 작동하지 않습니다. 많은 시도 끝에 마침내 WKWebview 쿠키를 설정하는 안정적인 방법을 찾았습니다.

먼저 WKProcessPool의 인스턴스를 만들고 WkWebview 자체를 초기화하는 데 사용할 WKWebViewConfiguration으로 설정해야합니다.

    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를 사용하려는 경우 마지막 문장에주의하십시오.

동일한 프로세스 풀이있는 웹보기는 결국 웹 콘텐츠 프로세스를 공유하게됩니다.

내가 의미하는 바는 동일한 도메인에 대해 WKWebView를 구성 할 때마다 WKProcessPool의 동일한 인스턴스를 사용하지 않는 경우 (WKWebView를 포함하는 VC A가 있고 다른 위치에 다른 VC A 인스턴스를 만들고 싶을 수 있음) ), 충돌 설정 쿠키가있을 수 있습니다. 문제를 해결하기 위해 도메인 B를로드하는 WKWebView에 대한 WKProcessPool을 처음 생성 한 후 단일 도메인에 저장하고 동일한 도메인 B를로드하는 WKWebView를 생성해야 할 때마다 동일한 WKProcessPool을 사용합니다.

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 : Dan Loewenherz의 환상적인 답변에서 확장 기능을 훔쳤습니다.

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

XHR 요청에 대한 더 나은 수정은 여기 에 표시 됩니다.

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

누군가 Alamofire를 사용하고 있다면 이것이 더 나은 솔루션입니다.

  let cookies = Alamofire.SessionManager.default.session.configuration.httpCookieStorage?.cookies(for: URL(string: BASE_URL)!)
  for (cookie) in cookies ?? [] {
      webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie)
  }

이것은 나를 위해 작동합니다 : setcookies 후 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))
                        }

                    })
                }

다중 쿠키 항목을 추가 할 때 다음과 같이 할 수 있습니다. ( 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];

그렇지 않으면 첫 번째 쿠키 항목 만 설정됩니다.


WKWebsiteDataStore를 사용하여 UIWebView에서 HTTPCookieStorage와 유사한 동작을 가져올 수도 있습니다.

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

아래 코드는 내 프로젝트 Swift5에서 잘 작동합니다. 아래 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)
    }

참고 URL : https://stackoverflow.com/questions/26573137/can-i-set-the-cookies-to-be-used-by-a-wkwebview

반응형