Сбой WKWebview getAllCookies в iOS 11.3

Недавно мы перешли на WKWebview. Мы добавили прослушиватель для изменения файлов cookie, чтобы получать обновленные файлы cookie и обновлять наш собственный магазин.

- (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore *)cookieStore {
    [cookieStore getAllCookies:^(NSArray* cookies) {
    }];
}

Как только контроллер загружается, он вызывает cookiesDidChangeInCookieStore и аварийно завершает работу в "getAllCookies". Но этот аварийный отказ происходит только в сборке TestFlight/Fabric. Не происходит, когда я запускаю приложение непосредственно на устройстве из xcode (как в режиме отладки, так и в режиме выпуска). Ниже приведен отчет о сбое,

Thread 9 name:  WebThread
Thread 9 Crashed:
0   WebKit                          0x0000000192fbfc10 WebKit::CallbackMap::put+ 1186832 (WTF::Ref<WebKit::CallbackBase, WTF::DumbPtrTraits<WebKit::CallbackBase> >&&) + 128
1   WebKit                          0x0000000192fbfbb4 WebKit::CallbackMap::put+ 1186740 (WTF::Ref<WebKit::CallbackBase, WTF::DumbPtrTraits<WebKit::CallbackBase> >&&) + 36
2   WebKit                          0x00000001930490cc WebKit::CallbackID WebKit::CallbackMap::put<WTF::Vector<WebCore::Cookie, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WebKit::CallbackBase::Error>(WTF::Function<void + 1749196 (WTF::Vector<WebCore::Cookie, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WebKit::CallbackBase::Error)>&&) + 136
3   WebKit                          0x0000000193049008 WebKit::WebCookieManagerProxy::getAllCookies(PAL::SessionID, WTF::Function<void + 1749000 (WTF::Vector<WebCore::Cookie, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&, WebKit::CallbackBase::Error)>&&) + 44
4   WebKit                          0x0000000192eb5b90 API::HTTPCookieStore::cookies(WTF::Function<void + 97168 (WTF::Vector<WebCore::Cookie, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&)>&&) + 124
5   WebKit                          0x00000001931fbdf8 -[WKHTTPCookieStore getAllCookies:] + 92
6   WebKit                          0x00000001931fc96c WKHTTPCookieStoreObserver::cookiesDidChange+ 3533164 (API::HTTPCookieStore&) + 44
7   WebKit                          0x0000000192eb61b0 API::HTTPCookieStore::cookiesDidChange+ 98736 () + 72
8   JavaScriptCore                  0x000000018a0e17d4 WTF::dispatchFunctionsFromMainThread+ 6100 () + 344
9   JavaScriptCore                  0x000000018a208650 WTF::timerFired+ 1214032 (__CFRunLoopTimer*, void*) + 40
10  CoreFoundation                  0x0000000183527aa8 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 28
11  CoreFoundation                  0x000000018352776c __CFRunLoopDoTimer + 864
12  CoreFoundation                  0x0000000183527010 __CFRunLoopDoTimers + 248
13  CoreFoundation                  0x0000000183524b60 __CFRunLoopRun + 2168
14  CoreFoundation                  0x0000000183444da8 CFRunLoopRunSpecific + 552
15  WebCore                         0x000000018b6d1dcc RunWebThread+ 265676 (void*) + 592
16  libsystem_pthread.dylib         0x00000001831a5220 _pthread_body + 272
17  libsystem_pthread.dylib         0x00000001831a5110 _pthread_body + 0
18  libsystem_pthread.dylib         0x00000001831a3b10 thread_start + 4

Похоже, что при вызове getAllCookies происходит переполнение. Это происходит только в iOS 11.3.


person spp    schedule 21.04.2018    source источник
comment
Похоже, вам нужно отправить отчет об ошибке в Apple, посмотрите, что они говорят: bugreport.apple.com   -  person Guy Kogus    schedule 21.04.2018
comment
Удалось решить этот сбой? Я столкнулся с той же проблемой.   -  person KrishnaKumar    schedule 27.04.2018
comment
См. решение внизу stackoverflow.com/questions/49954273/ и согласитесь, если это работает для вас. Выбранный ответ неверен, поскольку многопоточность не является решением :) спасибо!   -  person TurboManolo    schedule 24.04.2019


Ответы (2)


Я смог исправить этот сбой, вызвав getAllCookies асинхронно в основном потоке.

func cookiesDidChange(in cookieStore: WKHTTPCookieStore) {
     DispatchQueue.main.async {
         cookieStore.getAllCookies { (cookies) in
             //Code here...
         })
     }
}
person KrishnaKumar    schedule 27.04.2018
comment
это не решает сбой для меня. - person Gabriel.Massana; 04.06.2018
comment
Это не решает сбой, сбой не связан с многопоточностью. Пожалуйста, смотрите решение здесь > stackoverflow.com/questions/49954273/ - person TurboManolo; 28.03.2019

После некоторого исследования мы пришли к следующему рабочему решению:

Предыстория

У нас происходит сбой, когда пользователь обновляет до более новой версии нашего приложения.

Проблема

Мы использовали UIWebView и внедряли в него файлы cookie. Проблема возникает, когда:

  • Пользователь устанавливает новое обновленное приложение, которое использует WKWebview.
  • Пользователь открывает веб-представление.
  • Мы пытаемся получить все файлы cookie, ранее внедренные UIWebView, вызывая getAllCookies(_ completionHandler: @escaping ([HTTPCookie]) -> Void) в компоненте wkhttpcookiestore, чтобы мы могли перебирать их и удалять их один за другим.

Вердикт

UIWebView использует nshttpcookiestorage: https://developer.apple.com/documentation/foundation/nshttpcookiestorage

WKWebView использует wkhttpcookiestore: https://developer.apple.com/documentation/webkit/wkhttpcookiestore

Где-то в середине синхронизации от nshttpcookiestorage до wkhttpcookiestore, когда мы пытаемся получить файлы cookie, он передает одно из значений как NSURL, а затем кто-то вызывает функцию length() для этого объекта, который дает сбой, потому что NSURL не имеет этой функции.

разрешение

Поэтому мы должны удалить файлы cookie, установленные на nshttpcookiestorage, с помощью правильного метода, который заключается в использовании: HTTPCookieStorage.shared.removeCookies(since: Date.distantPast), а затем удалить файлы cookie с wkhttpcookiestore с помощью правильного метода, который является removeData(ofTypes:for:completionHandler:), и установить тип как WKWebsiteDataTypeCookies, а не перебирать все куки и удаляя их по одному.

Рекомендации по тестированию

Все тесты ДОЛЖНЫ выполняться на реальных устройствах (iPhone/iPad), поскольку этот сбой НЕ воспроизводим на симуляторах iOS.

Фрагмент кода

public func clearCookies(completion: @escaping (() -> Swift.Void)) {
    // First remove any previous cookies set in the NSHTTP cookie storage.
    HTTPCookieStorage.shared.removeCookies(since: Date.distantPast)
    // Second remove any previous cookies set in the WKHTTP cookie storage.
    let typeCookiesToBeRemoved: Set<String> = [WKWebsiteDataTypeCookies]
    // Only fetch the records in the storage with a cookie type.
    WKWebsiteDataStore.default().fetchDataRecords(ofTypes: typeCookiesToBeRemoved) { records in
        let dispatchGroup = DispatchGroup()
        records.forEach { record in
            dispatchGroup.enter()
            WKWebsiteDataStore.default().removeData(ofTypes: record.dataTypes, for: [record], completionHandler: {
                dispatchGroup.leave()
            })
        }
        dispatchGroup.notify(queue: DispatchQueue.main) {
            print("All cookies removed.")
            completion()
        }
    }
}
person TurboManolo    schedule 28.03.2019