iOS WKWebView - WKURLSchemeHandler 在 didReceiveResponse 上崩溃(EXC_BAD_ACCESS)

问题描述 投票:0回答:1

我使用 WKURLSchemeHandler 来处理一些内部请求(如主页、网页恢复等)。有时,当我拨打

urlSchemeTask.didReceive(urlResponse)
时,应用程序会崩溃并显示
EXC_BAD_ACCESS

这是调用堆栈:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
    frame #0: 0x00000001a7dd23a0 JavaScriptCore`WTF::StringImpl::hashSlowCase() const + 92
    frame #1: 0x00000001a7d8266c JavaScriptCore`WTF::HashTable<WTF::Packed<WTF::StringImpl*>, WTF::Packed<WTF::StringImpl*>, WTF::IdentityExtractor, WTF::DefaultHash<WTF::Packed<WTF::StringImpl*>>, WTF::HashTraits<WTF::Packed<WTF::StringImpl*>>, WTF::HashTraits<WTF::Packed<WTF::StringImpl*>>>::lookupForWriting(WTF::Packed<WTF::StringImpl*> const&) + 88
    frame #2: 0x00000001a7d82594 JavaScriptCore`WTF::HashTable<WTF::Packed<WTF::StringImpl*>, WTF::Packed<WTF::StringImpl*>, WTF::IdentityExtractor, WTF::DefaultHash<WTF::Packed<WTF::StringImpl*>>, WTF::HashTraits<WTF::Packed<WTF::StringImpl*>>, WTF::HashTraits<WTF::Packed<WTF::StringImpl*>>>::expand(WTF::Packed<WTF::StringImpl*>*) + 324
    frame #3: 0x00000001a7d835e8 JavaScriptCore`WTF::HashTableAddResult<WTF::HashTableIterator<WTF::Packed<WTF::StringImpl*>, WTF::Packed<WTF::StringImpl*>, WTF::IdentityExtractor, WTF::DefaultHash<WTF::Packed<WTF::StringImpl*>>, WTF::HashTraits<WTF::Packed<WTF::StringImpl*>>, WTF::HashTraits<WTF::Packed<WTF::StringImpl*>>>> WTF::HashTable<WTF::Packed<WTF::StringImpl*>, WTF::Packed<WTF::StringImpl*>, WTF::IdentityExtractor, WTF::DefaultHash<WTF::Packed<WTF::StringImpl*>>, WTF::HashTraits<WTF::Packed<WTF::StringImpl*>>, WTF::HashTraits<WTF::Packed<WTF::StringImpl*>>>::addPassingHashCode<WTF::HashSetTranslatorAdapter<WTF::UCharBufferTranslator>, WTF::HashTranslatorCharBuffer<char16_t> const&, WTF::HashTranslatorCharBuffer<char16_t> const&>(WTF::HashTranslatorCharBuffer<char16_t> const&, WTF::HashTranslatorCharBuffer<char16_t> const&) + 692
    frame #4: 0x00000001a7d8034c JavaScriptCore`WTF::AtomStringImpl::add(char16_t const*, unsigned int) + 240
    frame #5: 0x00000001a7d83e3c JavaScriptCore`WTF::AtomStringImpl::add(__CFString const*) + 332
    frame #6: 0x00000001aa7b5010 WebCore`WebCore::ResourceResponse::platformLazyInit(WebCore::ResourceResponseBase::InitLevel) + 336
    frame #7: 0x00000001a9f020ec WebKit`void WebCore::ResourceResponseBase::encode<IPC::Encoder>(IPC::Encoder&) const + 124
    frame #8: 0x00000001aa250a58 WebKit`bool WebKit::AuxiliaryProcessProxy::send<Messages::WebPage::URLSchemeTaskDidReceiveResponse>(Messages::WebPage::URLSchemeTaskDidReceiveResponse&&, unsigned long long, WTF::OptionSet<IPC::SendOption>) + 268
    frame #9: 0x00000001aa22c380 WebKit`WebKit::WebURLSchemeTask::didReceiveResponse(WebCore::ResourceResponse const&) + 192
    frame #10: 0x00000001aa106554 WebKit`WTF::Detail::CallableWrapper<-[WKURLSchemeTaskImpl didReceiveResponse:]::$_1, WebKit::WebURLSchemeTask::ExceptionType>::call() + 52
    frame #11: 0x00000001aa0fa7e4 WebKit`-[WKURLSchemeTaskImpl didReceiveResponse:] + 100
  * frame #12: 0x0000000104dab348 Browser`InternalSchemeHandler.webView(webView=0x000000010c853600, urlSchemeTask=__C.WKURLSchemeTask @ 0x000000016dd7c818, self=0x00000002808efe70) at InternalSchemeHandler.swift:98:27
    frame #13: 0x0000000104dabc64 Browser`@objc InternalSchemeHandler.webView(_:start:) at <compiler-generated>:0
    frame #14: 0x00000001aa1b8648 WebKit`WebKit::WebURLSchemeHandlerCocoa::platformStartTask(WebKit::WebPageProxy&, WebKit::WebURLSchemeTask&) + 524
    frame #15: 0x00000001aa20a0dc WebKit`WebKit::WebURLSchemeHandler::startTask(WebKit::WebPageProxy&, WebKit::WebProcessProxy&, WTF::ObjectIdentifier<WebCore::PageIdentifierType>, WebKit::URLSchemeTaskParameters&&, WTF::CompletionHandler<void (WebCore::ResourceResponse const&, WebCore::ResourceError const&, WTF::Vector<char, 0ul, WTF::CrashOnOverflow, 16ul, WTF::FastMalloc> const&)>&&) + 968
    frame #16: 0x00000001aa209cd0 WebKit`WebKit::WebPageProxy::startURLSchemeTaskShared(WTF::Ref<WebKit::WebProcessProxy, WTF::DumbPtrTraits<WebKit::WebProcessProxy>>&&, WTF::ObjectIdentifier<WebCore::PageIdentifierType>, WebKit::URLSchemeTaskParameters&&) + 108
    frame #17: 0x00000001aa209c24 WebKit`WebKit::WebPageProxy::startURLSchemeTask(WebKit::URLSchemeTaskParameters&&) + 52
    frame #18: 0x00000001aa4d44a8 WebKit`WebKit::WebPageProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 84824
    frame #19: 0x00000001a9ef885c WebKit`IPC::MessageReceiverMap::dispatchMessage(IPC::Connection&, IPC::Decoder&) + 124
    frame #20: 0x00000001aa2272f0 WebKit`WebKit::WebProcessProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 40
    frame #21: 0x00000001a9edbdec WebKit`IPC::Connection::dispatchMessage(std::__1::unique_ptr<IPC::Decoder, std::__1::default_delete<IPC::Decoder>>) + 656
    frame #22: 0x00000001a9edb6f4 WebKit`IPC::Connection::dispatchIncomingMessages() + 460
    frame #23: 0x00000001a7dbe3c8 JavaScriptCore`WTF::RunLoop::performWork() + 484
    frame #24: 0x00000001a7dbf0b0 JavaScriptCore`WTF::RunLoop::performWork(void*) + 36
    frame #25: 0x000000019db7076c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
    frame #26: 0x000000019db70668 CoreFoundation`__CFRunLoopDoSource0 + 208
    frame #27: 0x000000019db6f960 CoreFoundation`__CFRunLoopDoSources0 + 268
    frame #28: 0x000000019db69a8c CoreFoundation`__CFRunLoopRun + 824
    frame #29: 0x000000019db6921c CoreFoundation`CFRunLoopRunSpecific + 600
    frame #30: 0x00000001b4be8784 GraphicsServices`GSEventRunModal + 164
    frame #31: 0x00000001a05a2200 UIKitCore`-[UIApplication _run] + 1072
    frame #32: 0x00000001a05a7a74 UIKitCore`UIApplicationMain + 168
    frame #33: 0x000000010221d568 TDMBrowser`main at AppDelegate.swift:32:7
    frame #34: 0x000000019d8296c0 libdyld.dylib`start + 4

这是我的

URLSchemeHandler

    func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
        if taskDic[ObjectIdentifier(urlSchemeTask)] != false {
            taskDic[ObjectIdentifier(urlSchemeTask)] = true
        }

        guard let url = urlSchemeTask.request.url else {
            if taskDic[ObjectIdentifier(urlSchemeTask)] == true {
                urlSchemeTask.didFailWithError(InternalPageSchemeHandlerError.badURL)

                taskDic.removeValue(forKey: ObjectIdentifier(urlSchemeTask))
            }

            return
        }

        let path = url.path.starts(with: "/") ? String(url.path.dropFirst()) : url.path
        guard let responder = InternalSchemeHandler.responders[path] else {
            if taskDic[ObjectIdentifier(urlSchemeTask)] == true {
                urlSchemeTask.didFailWithError(InternalPageSchemeHandlerError.noResponder)

                taskDic.removeValue(forKey: ObjectIdentifier(urlSchemeTask))
            }

            return
        }
        guard let (urlResponse, data) = responder.response(forRequest: urlSchemeTask.request) else {
            if taskDic[ObjectIdentifier(urlSchemeTask)] == true {
                urlSchemeTask.didFailWithError(InternalPageSchemeHandlerError.responderUnableToHandle)

                taskDic.removeValue(forKey: ObjectIdentifier(urlSchemeTask))
            }

            return
        }

        if taskDic[ObjectIdentifier(urlSchemeTask)] == true {
            urlSchemeTask.didReceive(urlResponse)
            urlSchemeTask.didReceive(data)
            urlSchemeTask.didFinish()

            taskDic.removeValue(forKey: ObjectIdentifier(urlSchemeTask))
        }
    }

    func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
        moduleLogger.debug("stop urlSchemeTask: \(urlSchemeTask)")
        taskDic[ObjectIdentifier(urlSchemeTask)] = false
    }

任何人都可以帮助我避免这次崩溃吗?

wkwebview wkurlschemehandler
1个回答
0
投票

您现在可能已经明白了这一点,但您应该使用锁或以其他方式同步对字典的访问,并在获取锁时执行您的needed操作。我自己也遇到过同样的问题。

class TaskRegistry {
    private var lock = NSLock()
    private var tasks: [ObjectIdentifier: Bool] = [:]

    func withStorage(action: (inout [ObjectIdentifier: Bool]) -> Void) {
        lock.withLock {
          action(storage)
        }
    }
}

let registry = TaskRegistry()

func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
    moduleLogger.debug("stop urlSchemeTask: \(urlSchemeTask)")
    registry.withStorage {
      $0[ObjectIdentifier(urlSchemeTask)] = false
    }
}

func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
    registry.withStorage {
      if $0[ObjectIdentifier(urlSchemeTask)] != false {
          $0[ObjectIdentifier(urlSchemeTask)] = true
      }
    }

    guard let url = urlSchemeTask.request.url else {
        registry.withStorage {
            if $0[ObjectIdentifier(urlSchemeTask)] == true {           
                urlSchemeTask.didFailWithError(InternalPageSchemeHandlerError.badURL)
                $0.removeValue(forKey: ObjectIdentifier(urlSchemeTask))
            }
        }
        return
    }

    let path = url.path.starts(with: "/") ? String(url.path.dropFirst()) : url.path
    guard let responder = InternalSchemeHandler.responders[path] else {
        registry.withStorage {
            if $0[ObjectIdentifier(urlSchemeTask)] == true {
                urlSchemeTask.didFailWithError(InternalPageSchemeHandlerError.noResponder)
                $0.removeValue(forKey: ObjectIdentifier(urlSchemeTask))
            }
        }
        return
    }
    guard let (urlResponse, data) = responder.response(forRequest: urlSchemeTask.request) else {
        registry.withStorage {
            if $0[ObjectIdentifier(urlSchemeTask)] == true {          
                urlSchemeTask.didFailWithError(
                    InternalPageSchemeHandlerError.responderUnableToHandle
                )

                $0.removeValue(forKey: ObjectIdentifier(urlSchemeTask))
            }
        }

        return
    }

    registry.withStorage {
        if $0[ObjectIdentifier(urlSchemeTask)] == true {
            urlSchemeTask.didReceive(urlResponse)
            urlSchemeTask.didReceive(data)
            urlSchemeTask.didFinish()

            $0.removeValue(forKey: ObjectIdentifier(urlSchemeTask))
        }
    }
}

如果您不需要支持 iOS 16 之前的版本,

OSAllocatedUnfairLock
有类似的 API。

© www.soinside.com 2019 - 2024. All rights reserved.