Explore the integration of web technologies within your app. Discuss building web-based apps, leveraging Safari functionalities, and integrating with web services.

General Documentation

Posts under General subtopic

Post

Replies

Boosts

Views

Activity

What makes Safari render an active extension's icon in color in the toolbar?
Sometimes Safari is rendering the icon for an active extension in its original provided colored representation, other times Safari is applying an overlay color in line with the system's highlight color. This difference can even be seen seen on the Safari Extensions Developer home page: https://developer.apple.com/safari/extensions/images/extensions-hero-large_2x.png You will notice that Grammarly's icon is shown in it's original color format, while the others aren't. Example of extensions where the icon is shown in color: Bitwarden Grammarly 1Password Consent-O-Matic I've compared the source code of Bitwarden and Consent-o-Matic with my own extension and cannot find any differences in the settings or image properties (resolution, DPI, file type, color profile). If I take the exact PNG source files from said open source extensions and replace them in my own source code, these icons show up in full color. Does this perhaps mean there is a bug in Safari's processing of the icons where it fails to overlay the icon with the highlight color in some cases? I and I assume many developers with me would like to understand what determines this difference. Ideally, there is a consistent UX where the end user has the choice between icons in color or highlight color overlay.
3
0
1.2k
Mar ’25
Request for Native AJAX API Request Interception Support in WKWebView
Hello WebKit Team, I’m writing to ask if iOS provides a native way to intercept AJAX (XMLHttpRequest or fetch) calls inside WKWebView. On Android, this is handled via: shouldInterceptRequest(WebView view, WebResourceRequest request) but iOS currently seems to have no equivalent. We’ve tried: WKURLSchemeHandler → works only for custom schemes URLProtocol with WKProcessPool → unreliable for AJAX in WebView JavaScript injection → partial and unofficial Could you please clarify: Is there a recommended native approach to intercept AJAX requests? If not supported, is it planned for future releases? Any official workaround or guidance? This is critical for debugging, analytics, and compliance in hybrid apps.
3
0
989
Dec ’25
Safe areas ignored after navigating a WebView/WebPage back in a NavigationStack
I'm using the new iOS 26 WebPage/WebView for SwiftUI in a NavigationStack. The initial load works as expected, but when loading items from the back/forward lists, the content jumps beneath the navigation bar: struct WebPageTestView: View { var webPage = WebPage() var body: some View { NavigationStack { WebView(webPage) .toolbar { Button("Back") { if let backItem = webPage.backForwardList.backList.last { webPage.load(backItem) } } Button("Forward") { if let forwardItem = webPage.backForwardList.forwardList.first { webPage.load(forwardItem) } } } } .task { webPage.isInspectable = true webPage.load(URL(string: "https://domchristie.co.uk/")) } } } I have run this on the iOS 26.0 and 26.1 Simulators and get the same issue. The demo website does not use any JavaScript. I was able to replicate this behaviour using a wrapped WKWebView and calling the .ignoresSafeArea(.all) modifier.
3
1
561
Oct ’25
macOS 26 beta 4 and iOS 26 beta 4 - WebKit XML parser crashes parsing XHTML with namespaces
Our app, VitalSource Bookshelf, is an EPUB reader that uses a WKWebView to display book content. The EPUB content format is XHTML and uses namespaces (for the epub:type declaration). On beta 4, the webkit process repeatedly crashes when loading our content. The crash appears to be in the XML parser. Here's what's at the top of the stack trace: 0 WebCore 0x19166a878 WebCore::XMLDocumentParser::startElementNs(unsigned char const*, unsigned char const*, unsigned char const*, int, unsigned char const**, int, int, unsigned char const**) + 4968 1 libxml2.2.dylib 0x19c5a2bd0 xmlParseStartTag2 + 3940 2 libxml2.2.dylib 0x19c59e730 xmlParseTryOrFinish + 2984 3 libxml2.2.dylib 0x19c59d8e4 xmlParseChunk + 708 4 WebCore 0x191668ec8 WebCore::XMLDocumentParser::doWrite(WTF::String const&) + 636 5 WebCore 0x191665b78 WebCore::XMLDocumentParser::append(WTF::RefPtr<WTF::StringImpl, WTF::RawPtrTraits<WTF::StringImpl>, WTF::DefaultRefDerefTraits<WTF::StringImpl>>&&) + 304 6 WebCore 0x190105db0 WebCore::DecodedDataDocumentParser::appendBytes(WebCore::DocumentWriter&, std::__1::span<unsigned char const, 18446744073709551615ul>) + 268 7 WebCore 0x190861c3c WebCore::DocumentLoader::commitData(WebCore::SharedBuffer const&) + 1488 8 WebKit 0x18e07ca3c WebKit::WebLocalFrameLoaderClient::committedLoad(WebCore::DocumentLoader*, WebCore::SharedBuffer const&) + 52 9 WebCore 0x190869db4 WebCore::DocumentLoader::commitLoad(WebCore::SharedBuffer const&) + 228 10 WebCore 0x1909521e4 WebCore::CachedRawResource::notifyClientsDataWasReceived(WebCore::SharedBuffer const&) + 268 I was able to reproduce this in Safari on beta 4 just by opening the following trivial xhtml file from the file system - it does the same thing it does in our app, which is reloads and crashes several times, followed by the "A problem repeatedly occurred with..." error message. <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" epub:prefix="vst: http://vitalsource.com/"><head></head><body class="dash" epub:type="chapter" data-begin-o="0" data-begin-o2="0" data-begin-o3="0" data-o="0" id="eid1844" data-end-o="14703" data-end-o2="14703" data-end-o3="14703"><h2 class="title" data-o="0" id="eid1845" data-out="33"><span class="label" data-o="0" id="eid1846"><span class="label-inner"><b data-o="0" id="eid1847">CHAPTER X</b> </span></span>THE SUBMARINE COAL-MINES</h2></body></html> I've also filed a feedback. But posting here just to raise the visibility - this is critical for us. I think it was introduced in beta 4; that's at least when we first noticed it. It was working in the earlier betas, I just don't remember if I tried beta 3 or not. It happens on iOS, macOS, and iPadOS. This has never been a problem in any earlier release of macOS / iOS.
Topic: Safari & Web SubTopic: General
3
1
517
Aug ’25
WKWebView requires authentication
I use WKWebView to display a webpage that requires authentication through an authentication provider. This works as expected, but when I close and reopen the app, I have to reauthenticate. However, if I open the same page in Safari, I only have to authenticate once. If I close Safari and reopen it, the page displays without prompting me to authenticate again. I see some cookies stored in httpCookieStore, so I assume that storing cookies works. Does anyone have an idea why authentication is not persistent between app launches? Thanks in advance. Best regards, Marc
Topic: Safari & Web SubTopic: General Tags:
3
0
170
Jul ’25
WKBrowsingContextController is invalid
Is this code invalid on a phone running xcode16 iOS18? Class cls = NSClassFromString(@"WKBrowsingContextController"); SEL sel = NSSelectorFromString(@"registerSchemeForCustomProtocol:"); if ([(id)cls respondsToSelector:sel]) { [(id)cls performSelector:sel withObject:@"http"]; [(id)cls performSelector:sel withObject:@"https"]; } }
Topic: Safari & Web SubTopic: General
3
0
147
Jun ’25
header and footer positions shifted in Safari tab settings
Thank you for supporting me. My environment Device: iPhone 15 Pro OS: iOS 26.0 Public Beta (23A5336a) In iOS 26, three types of tabs were added to Safari. Depending on the option, the behavior of the fixed header and footer can be unstable. *Tab settings can be changed in the iOS Settings app under "Apps -> Safari" > "Tabs." The following behavior differs depending on the tab. Compact When scrolling down, the header and footer shift up by a few pixels. A margin is created between the footer and the URL input field. Bottom Behaves the same as "Compact." Top The header is completely hidden below the URL input field at the top of the screen, leaving a margin below the footer. Below is the sample code to check the operation. <!doctype html> <html lang="ja"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>固定ヘッダー/フッター + モーダル</title> <style> :root { --header-h: 56px; --footer-h: 56px; } body { margin: 0; font-family: sans-serif; line-height: 1.6; background: #f9fafb; padding-top: var(--header-h); padding-bottom: var(--footer-h); } header .inner, footer .inner { width: 100%; max-width: var(--max-content-w); padding: 0 16px; display: flex; align-items: center; justify-content: space-between; } header, footer { position: fixed; left: 0; right: 0; display: flex; align-items: center; justify-content: center; z-index: 100; background: #fff; } header { top: 0; height: var(--header-h); border-bottom: 1px solid #ddd; } footer { bottom: 0; height: var(--footer-h); border-top: 1px solid #ddd; } main { padding: 16px; } .btn { padding: 8px 16px; border: 1px solid #2563eb; background: #2563eb; color: #fff; border-radius: 6px; cursor: pointer; } /* モーダル関連 */ .modal { position: fixed; inset: 0; display: none; z-index: 1000; } .modal.is-open { display: block; } .modal__backdrop { position: absolute; inset: 0; background: rgba(0,0,0,0.5); } .modal__panel { position: relative; max-width: 600px; margin: 10% auto; background: #fff; border-radius: 8px; padding: 20px; z-index: 1; } .modal__head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .modal__title { margin: 0; font-size: 18px; font-weight: bold; } .modal__close { background: none; border: none; font-size: 20px; cursor: pointer; } </style> </head> <body> <header> <div class="inner"> <h1>デモページ</h1> <button id="openModal" class="btn">モーダルを開く</button> </div> </header> <main class="container" id="main"> <h2>スクロール用の適当なコンテンツ1</h2> <p>ヘッダーとフッターは常に表示されます。モーダルボタンを押すと、画面いっぱいのダイアログが開きます。</p> <!-- ダミーカードを複数 --> <section class="grid"> <div class="card"><strong>カード1</strong><p>適当なテキスト。適当なテキスト。適当なテキスト。</p></div> <div class="card"><strong>カード2</strong><p>適当なテキスト。適当なテキスト。適当なテキスト。</p></div> <div class="card"><strong>カード3</strong><p>適当なテキスト。適当なテキスト。適当なテキスト。</p></div> <div class="card"><strong>カード4</strong><p>適当なテキスト。適当なテキスト。適当なテキスト。</p></div> <div class="card"><strong>カード5</strong><p>適当なテキスト。適当なテキスト。適当なテキスト。</p></div> <div class="card"><strong>カード6</strong><p>適当なテキスト。適当なテキスト。適当なテキスト。</p></div> <div class="card"><strong>カード7</strong><p>適当なテキスト。適当なテキスト。適当なテキスト。</p></div> <div class="card"><strong>カード8</strong><p>適当なテキスト。適当なテキスト。適当なテキスト。</p></div> <div class="card"><strong>カード9</strong><p>適当なテキスト。適当なテキスト。適当なテキスト。</p></div> <div class="card"><strong>カード10</strong><p>適当なテキスト。適当なテキスト。適当なテキスト。</p></div> </section> </main> <footer> <small>&copy; 2025 Demo</small> </footer> <!-- モーダル --> <div class="modal" id="modal"> <div class="modal__backdrop"></div> <div class="modal__panel"> <div class="modal__head"> <h2 class="modal__title">モーダル</h2> <button class="modal__close" id="closeModal">&times;</button> </div> <p>これは白いビューのモーダルです。背景は黒く半透明で覆われています。</p> </div> </div> <script> const modal = document.getElementById('modal'); const openBtn = document.getElementById('openModal'); const closeBtn = document.getElementById('closeModal'); const backdrop = modal.querySelector('.modal__backdrop'); openBtn.addEventListener('click', () => { modal.classList.add('is-open'); }); function closeModal() { modal.classList.remove('is-open'); } closeBtn.addEventListener('click', closeModal); backdrop.addEventListener('click', closeModal); window.addEventListener('keydown', (e) => { if (e.key === 'Escape' && modal.classList.contains('is-open')) { closeModal(); } }); </script> </body> </html>
3
0
834
Sep ’25
browser.runtime.onMessage in content script intermittently fails on iOS 18.5 (Safari Web Extensions)
Hi everyone, I’m encountering a critical reliability issue with message passing in my Safari Web Extension on iOS 18.4.1 and iOS 18.5. In my extension, I’m using the standard messaging API. The background script sends a message to the content script using browser.tabs.sendMessage(...), and the content script registers a listener via: browser.runtime.onMessage.addListener(handler); This setup has been working reliably in all prior versions of iOS. However, after updating to iOS 18.4.1 and 18.5, I’ve noticed the following behavior: ✅ The content script is successfully injected, and onMessage.addListener is registered (I see logging confirming this). ✅ The background script sends the message using the correct tabId (also confirmed via logs). ❌ The content script’s onMessage listener is not consistently triggered. ⚠️ This issue is intermittent, sometimes the message is received, sometimes it is silently dropped. ❌ No exceptions or errors are thrown in either script, the message appears to be sent, but not picked up from the content script message listener.
3
3
294
Jul ’25
WKWebView crashes on iOS 26 with EXC_BAD_ACCESS
Hi, I have an app that uses WKWebView and it's crashing on iOS 26 Simulator in places I've never had problems before. In this case it's crashing when calling WKWebView.callAsyncJavaScript, but in my other project WKWebView is crashing with some sort of EXC_BAD_ACCESS other than callAsyncJavaScript. Am I missing something? Thanks,
Topic: Safari & Web SubTopic: General
3
1
301
Jun ’25
WKWebView crash on iOS 26 Beta with -webkit-user-select: none
On iOS 26 Beta, WKWebView consistently crashes when interacting with pages that use -webkit-user-select: none. This issue does not reproduce in Safari, but only when the same content is loaded inside a WKWebView. Steps to Reproduce: Install iOS 26 Beta. Open a WKWebView that loads a webpage with the following style applied globally: -webkit-user-select: none; Perform the following gesture sequence inside the WKWebView: Double tap anywhere in the web content. On the second tap, keep your finger pressed (do not lift). While still holding the second tap, drag your finger across the screen (pan). This sequence reliably produces the crash. Expected Result: No crash. The gesture should either be ignored or handled gracefully. Actual Result: The app crashes 100% of the time with the following exception: #0 0x000000013f1a0874 in __pthread_kill () #1 0x00000001357522ec in pthread_kill () #2 0x00000001801ad950 in abort () #3 0x00000001802fa26c in __abort_message () #4 0x00000001802ea1a4 in demangling_terminate_handler () #5 0x0000000180077218 in _objc_terminate () #6 0x00000001802f9758 in std::__terminate () #7 0x00000001802fc7c0 in __cxxabiv1::failed_throw () #8 0x00000001802fc7a0 in __cxa_throw () #9 0x000000018009c1bc in objc_exception_throw () #10 0x00000001804f38f8 in +[NSException raise:format:] () #11 0x000000018c5fb570 in -[CALayer setPosition:] () #12 0x0000000185d02414 in -[UIView _backing_setPosition:] () #13 0x00000001867ec978 in -[UIView setCenter:] () #14 0x0000000186666468 in -[_UIEditMenuContentPresentation _displayPreparedMenu:titleView:reason:didDismissMenu:configuration:] () #15 0x0000000186666088 in __54-[_UIEditMenuContentPresentation _displayMenu:reason:]_block_invoke () #16 0x00000001867b3ed4 in -[UIEditMenuInteraction _editMenuPresentation:preparedMenuForDisplay:completion:] () #17 0x0000000186665fb0 in -[_UIEditMenuContentPresentation _displayMenu:reason:] () #18 0x0000000186665de4 in -[_UIEditMenuContentPresentation displayMenu:configuration:] () #19 0x00000001867b3260 in __58-[UIEditMenuInteraction presentEditMenuWithConfiguration:]_block_invoke () #20 0x00000001867b4c98 in __80-[UIEditMenuInteraction _prepareMenuAtLocation:configuration:completionHandler:]_block_invoke () #21 0x000000018653ff80 in __109-[UITextContextMenuInteraction _editMenuInteraction:menuForConfiguration:suggestedActions:completionHandler:]_block_invoke () #22 0x0000000186540448 in __107-[UITextContextMenuInteraction _querySelectionCommandsForConfiguration:suggestedActions:completionHandler:]_block_invoke () #23 0x000000018dba84f8 in WTF::Detail::CallableWrapper<WTF::CompletionHandler<void (IPC::Connection*, IPC::Decoder*)> IPC::Connection::makeAsyncReplyCompletionHandler<Messages::WebPage::RequestDocumentEditingContext, WTF::CompletionHandler<void (WebKit::DocumentEditingContext&&)>>(WTF::CompletionHandler<void (WebKit::DocumentEditingContext&&)>&&, WTF::ThreadLikeAssertion)::'lambda'(IPC::Connection*, IPC::Decoder*), void, IPC::Connection*, IPC::Decoder*>::call () #24 0x000000018dca14cc in WTF::Detail::CallableWrapper<WebKit::AuxiliaryProcessProxy::sendMessage(WTF::UniqueRef<IPC::Encoder>&&, WTF::OptionSet<IPC::SendOption>, std::__1::optional<IPC::ConnectionAsyncReplyHandler>, WebKit::AuxiliaryProcessProxy::ShouldStartProcessThrottlerActivity)::$_1, void, IPC::Connection*, IPC::Decoder*>::call () #25 0x000000018e2d5c54 in IPC::Connection::dispatchMessage () #26 0x000000018e2d6118 in IPC::Connection::dispatchIncomingMessages () #27 0x00000001997f9c58 in WTF::RunLoop::performWork () #28 0x00000001997fa930 in WTF::RunLoop::performWork () #29 0x000000018044d4dc in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ () #30 0x000000018044d424 in __CFRunLoopDoSource0 () #31 0x000000018044cc0c in __CFRunLoopDoSources0 () #32 0x000000018044bd84 in __CFRunLoopRun () #33 0x0000000180446e24 in _CFRunLoopRunSpecificWithOptions () #34 0x00000001924c19bc in GSEventRunModal () #35 0x00000001862217a8 in -[UIApplication _run] () #36 0x00000001862259d0 in UIApplicationMain () Same issues below. https://developer.apple.com/forums/thread/796799 https://developer.apple.com/forums/thread/796501 https://developer.apple.com/forums/thread/796874 https://developer.apple.com/forums/thread/796686
3
4
1.2k
Aug ’25
Accessing WKNavigationAction.sourceFrame.request crashes
Hi all, I'm currently working with WKWebView and implementing the WKNavigationDelegate protocol. In particular, I'm trying to inspect the sourceFrame of a WKNavigationAction to make navigation policy decisions based on the frame's URL path. Here's the relevant Swift code inside decidePolicyFor: public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences) -> Void) { // ... let sourceFrame: WKFrameInfo = navigationAction.sourceFrame let request: URLRequest = sourceFrame.request // <- SIGABRT occurs here // ... } The issue is that the app crashes with a SIGABRT at runtime when attempting to access sourceFrame.request. According to Swift's type system, neither sourceFrame nor its request property are optional, so at first glance this seems safe. However, the crash report suggests otherwise. From the crash log, it appears that the issue arises during the bridging from Objective-C to Swift: Thread 1 Queue : com.apple.main-thread (serial) #0 0x00000001a127a030 in static Foundation.URLRequest._unconditionallyBridgeFromObjectiveC(Swift.Optional<__C.NSURLRequest>) -> Foundation.URLRequest () #1 0x00000001056c48b0 in CustomWebViewController.webView(_:decidePolicyFor:preferences:decisionHandler:) #2 0x00000001056c4c78 in @objc CustomWebViewController.webView(_:decidePolicyFor:preferences:decisionHandler:) () #3 0x00000001b8c66e0c in WebKit::NavigationState::NavigationClient::decidePolicyForNavigationAction () #4 0x00000001b8fd14dc in WebKit::WebPageProxy::decidePolicyForNavigationAction () #5 0x00000001b8fcfc7c in WebKit::WebPageProxy::decidePolicyForNavigationActionAsyncShared () #6 0x00000001b8fcfb18 in WebKit::WebPageProxy::decidePolicyForNavigationActionAsync () #7 0x00000001b87ddaa0 in WebKit::WebPageProxy::didReceiveMessage () #8 0x00000001b869f474 in IPC::MessageReceiverMap::dispatchMessage () #9 0x00000001b878dda4 in WebKit::WebProcessProxy::dispatchMessage () #10 0x00000001b878d614 in WebKit::WebProcessProxy::didReceiveMessage () #11 0x00000001b869e7e4 in IPC::Connection::dispatchMessage () #12 0x00000001b869e358 in IPC::Connection::dispatchIncomingMessages () #13 0x00000001b9a96a44 in WTF::RunLoop::performWork () #14 0x00000001b9a96688 in WTF::RunLoop::performWork () #15 0x00000001a2428b9c in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ () #16 0x00000001a24289b4 in __CFRunLoopDoSource0 () #17 0x00000001a2428810 in __CFRunLoopDoSources0 () #18 0x00000001a2429190 in __CFRunLoopRun () #19 0x00000001a242ad4c in CFRunLoopRunSpecific () #20 0x00000001ef705454 in GSEventRunModal () #21 0x00000001a4e45890 in -[UIApplication _run] () #22 0x00000001a4e10cec in UIApplicationMain () #23 0x00000001a4ef261c in ___lldb_unnamed_symbol275689 () #24 0x00000001059a5104 in static UIApplicationDelegate.main() () #25 0x00000001059a5074 in static AppDelegate.$main() () #26 0x00000001059a82ec in main () #27 0x00000001c940af0c in start () This implies that while Swift treats sourceFrame.request as non-optional, the underlying Objective-C implementation may actually return nil—leading to a crash when the non-optional Swift type attempts to force unwrap it. My question: Is there a way to safely access navigationAction.sourceFrame.request —- or determine if it’s nil—before Swift attempts the implicit bridging from Objective-C? Or is there an established workaround for safely inspecting this property? Any guidance or best practices for avoiding this crash would be greatly appreciated! Thanks in advance.
Topic: Safari & Web SubTopic: General Tags:
3
0
139
Apr ’25
Safari Web Extension: This extension can read ... including passwords...
I want to migrate from a Safari App Extension to a Safari Web Extension, but don't know how to get rid of the message, telling users that my extension can access their passwords. Here is a message which I see: I was thinking that this might be because all Safari Web Extension get this type of access, but I have a Safari Web Extension which does not require such level of access: Here is the manifest: { "manifest_version": 2, "default_locale": "en", "name": "__MSG_extension_name__", "description": "__MSG_extension_description__", "version": "1.1", "icons": { "48": "images/icon-48.png" }, "background": { "scripts": [ "background.js" ], "persistent": true }, "browser_action": { "default_popup": "popup.html", "default_icon": { "16": "images/toolbar-icon-16.png" } }, "permissions": [ "nativeMessaging", "tabs" ] } and here is the Info.plist file: Here is the entire code of the extension: https://github.com/kopyl/web-extension-simplified
3
0
541
Jan ’26
iOS26 wkWebview Crash CALayer position contains NaN
On my native app, will open a wkWebview to display some content. And it will crash on iOS26: *** Terminating app due to uncaught exception 'CALayerInvalidGeometry', reason: 'CALayer position contains NaN: [nan 103.667]. Layer: <CALayer:0x14c2457d0; position = CGPoint (0 0); bounds = CGRect (0 0; 0 48); delegate = <_UIEditMenuListView: 0x14c273980; frame = (nan 0; 0 48); anchorPoint = (inf, 0); alpha = 0; layer = <CALayer: 0x14c2457d0>>; sublayers = (<CALayer: 0x1306320a0>, <CALayer: 0x14c245a70>); opaque = YES; allowsGroupOpacity = YES; anchorPoint = CGPoint (inf 0); opacity = 0>'
Topic: Safari & Web SubTopic: General Tags:
3
5
469
Aug ’25
IOS 26, web extensions no longer available
I recently upgraded my device from IOS 18.4 to IOS 26. My web extension has disapeared from safari. I can see it in Settings > Apps > Safari > Extensions and when I turn it on and re-open safari. I just get a mesasge that says "{extension name} is no longer avaiable". I have tried Manifest V2 and Manifest V3 both yield the same results. The current production extension bundled with the IOS app has the same problem. I can no longer use or test my own extension !? Help please !
3
1
551
Jul ’25
Detecting Navigation Redirect Chains
I'm building a macOS extension that needs to track multi-step navigation chains (A → B → C) to adjust behavior based on where users came from. Current approach: Using webNavigation.onBeforeNavigate to detect intermediate steps, but experiencing issues in Safari that don't occur on Chrome/Firefox/Edge. Questions: Is webNavigation the right API for tracking redirect chains in Safari? Does ITP/Private Browsing affect event delivery? Any alternative approaches recommended? (Safari version 26.0.1) Any guidance appreciated!
3
0
846
Dec ’25
@@extension_id replacement in CSS file fails in Sequoia, Safari 18
Typically, you can use the @@extension_id special string to reference the absolute path into the bundled resources of an extension, such as an image or a custom font, in a CSS file. However, this broke with Safari 18. Consider this section in a popup.css file: .card-icon { height: 16px; width: 20px; background-image: url(safari-web-extension://__MSG_@@extension_id__/images/card.svg); background-size: 20px 16px; } In Safari 17.4, once loaded in the browser, @@extension_id is replaced with E8BEA491-9B80-45DB-8B20-3E586473BD47, and the background-image reads as so: background-image: url(safari-web-extension://E8BEA491-9B80-45DB-8B20-3E586473BD47/images/card.svg); But as of Safari 18, the @@extension_id just collapses to an empty string, and the background-image reads as so: background-image: url(safari-web-extension:///images/card.svg); and the svg fails to load with the following error: "Failed to load resource: You do not have permission to access the requested resource." This is a regression, does to match the behavior of the other major browsers, and should be fixed. Filed with Feedback ID: FB15104807
3
1
877
Apr ’25
WKNavigationActionPolicy of "cancel" prints stack trace to console
Starting in iOS 26 (tested on 26.1), when I use any of the “policy” methods of WKNavigationDelegate to return an action policy of cancel I get a trace like this printed to console: 1 0x18de71bbc WebKit::WebFramePolicyListenerProxy::ignore(WebKit::WasNavigationIntercepted) 2 0x18db3dd50 WebKit::NavigationState::NavigationClient::decidePolicyForNavigationAction(WebKit::WebPageProxy&, WTF::Ref<API::NavigationAction, WTF::RawPtrTraits<API::NavigationAction>, WTF::DefaultRefDerefTraits<API::NavigationAction>>&&, WTF::Ref<WebKit::WebFramePolicyListenerProxy, WTF::RawPtrTraits<WebKit::WebFramePolicyListenerProxy>, WTF::DefaultRefDerefTraits<WebKit::WebFramePolicyListenerProxy>>&&)::$_0::operator()(WKNavigationActionPolicy, WKWebpagePreferences*) 3 0x100189e5c $sSo24WKNavigationActionPolicyVIeyBhy_ABIeghy_TR 4 0x100189d38 $s16WebkitPolicyTrap14ViewControllerC03webD0_06decideB3For15decisionHandlerySo05WKWebD0C_So18WKNavigationActionCySo0lmB0VctF 5 0x100189df4 $s16WebkitPolicyTrap14ViewControllerC03webD0_06decideB3For15decisionHandlerySo05WKWebD0C_So18WKNavigationActionCySo0lmB0VctFTo 6 0x18db255c0 WebKit::NavigationState::NavigationClient::decidePolicyForNavigationAction(WebKit::WebPageProxy&, WTF::Ref<API::NavigationAction, WTF::RawPtrTraits<API::NavigationAction>, WTF::DefaultRefDerefTraits<API::NavigationAction>>&&, WTF::Ref<WebKit::WebFramePolicyListenerProxy, WTF::RawPtrTraits<WebKit::WebFramePolicyListenerProxy>, WTF::DefaultRefDerefTraits<WebKit::WebFramePolicyListenerProxy>>&&) 7 0x18dea9848 WebKit::WebPageProxy::decidePolicyForNavigationAction(WTF::Ref<WebKit::WebProcessProxy, WTF::RawPtrTraits<WebKit::WebProcessProxy>, WTF::DefaultRefDerefTraits<WebKit::WebProcessProxy>>&&, WebKit::WebFrameProxy&, WebKit::NavigationActionData&&, WTF::CompletionHandler<void (WebKit::PolicyDecision&&)>&&) 8 0x18dea7a34 WebKit::WebPageProxy::decidePolicyForNavigationActionAsync(IPC::Connection&, WebKit::NavigationActionData&&, WTF::CompletionHandler<void (WebKit::PolicyDecision&&)>&&) 9 0x18d9cbbf4 void IPC::handleMessageAsync<Messages::WebPageProxy::DecidePolicyForNavigationActionAsync, IPC::Connection, WebKit::WebPageProxy, WebKit::WebPageProxy, void (IPC::Connection&, WebKit::NavigationActionData&&, WTF::CompletionHandler<void (WebKit::PolicyDecision&&)>&&)>(IPC::Connection&, IPC::Decoder&, WebKit::WebPageProxy*, void (WebKit::WebPageProxy::*)(IPC::Connection&, WebKit::NavigationActionData&&, WTF::CompletionHandler<void (WebKit::PolicyDecision&&)>&&)) 10 0x18d9c7728 WebKit::WebPageProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) 11 0x18e49a0d8 IPC::MessageReceiverMap::dispatchMessage(IPC::Connection&, IPC::Decoder&) 12 0x18df1908c WebKit::WebProcessProxy::dispatchMessage(IPC::Connection&, IPC::Decoder&) 13 0x18d9dfc28 WebKit::WebProcessProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) 14 0x18e47f72c IPC::Connection::dispatchMessage(WTF::UniqueRef<IPC::Decoder>) 15 0x18e47fac4 IPC::Connection::dispatchIncomingMessages() 16 0x199ad3758 WTF::RunLoop::performWork() 17 0x199ad4eb0 WTF::RunLoop::performWork(void*) 18 0x1804563a4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ 19 0x1804562ec __CFRunLoopDoSource0 20 0x180455a78 __CFRunLoopDoSources0 21 0x180454c4c __CFRunLoopRun 22 0x18044fcec _CFRunLoopRunSpecificWithOptions 23 0x1926be9bc GSEventRunModal 24 0x18630f0d8 -[UIApplication _run] 25 0x186313300 UIApplicationMain 26 0x18554ac38 block_destroy_helper.15 27 0x10018a70c $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ 28 0x10018a67c $s16WebkitPolicyTrap11AppDelegateC5$mainyyFZ 29 0x10018a818 __debug_main_executable_dylib_entry_point 30 0x1000cd3d0 29 dyld 0x00000001000cd3d0 start_sim + 20 31 0x1002bab98 30 ??? 0x00000001002bab98 0x0 + 4297829272 This doesn’t happen in 18.6. Also, it doesn’t seem to have any negative consequences other than the console spam? But then, the navigation is being cancelled anyway, so maybe it’s trapping and just happens to have the effect of not loading the request? Anyway, I guess I can’t upload zips. But it’s pretty easy to reproduce. Just assign a WKWebView a navigationDelegate with an implementation like: func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping @MainActor (WKNavigationActionPolicy) -> Void) { decisionHandler(.cancel) } and then have it .load() anything. Have I been doing this wrong and 26 exposes it? Or is this a bug in 26? If the latter, any downstream consequences I should be looking out for? macOS 15.7.1 (24G231) Xcode 26.1.1 (17B100) iOS 26.1 (23B86)
Topic: Safari & Web SubTopic: General Tags:
3
0
1.1k
Dec ’25
Enable a Developer ID-signed and notarised extension without enabling "allow unsigned extension"
Hello, According to the documentation: If you provide your extension in macOS and don’t want to use the Mac App Store for distribution, you can sign and notarize your extension’s app with a Developer ID to distribute it outside the Mac App Store. However, I found this to be untrue in practice. Even after signing and notarising the Safari extension correctly, it is not possible to enable it in Safari without turning on "allow unsigned extension". This makes it impossible to distribute your Developer ID–signed and notarized extension outside the Mac App Store. I would like to distribute my web extension directly to employees in my organization using MDM without having each user manually enable "allow unsigned extension" for it to work. Any way to make it work? The documentation is quite confusing in this aspect, it says "Safari only supports signed extensions" but my extension is rejected even if notarised and signed.
3
0
166
Apr ’25
WKNavigationAction.sourceFrame is nil on iOS 15.4 & 16.6 despite non-optional Swift declaration (fixed in iOS 18.6)
Reproducibility 100% on iOS 15.4 and iOS 16.6 Zero crash on iOS 18.6 Xcode 26.1 Steps to Reproduce Xcode 26.1 → New iOS App Replace ViewController.swift with the 20-line code below Run on real device • iPhone XR iOS 15.4 • iPhone 13 iOS 16.6 Tap the link → breakpoint in decidePolicyFor lldb → po navigationAction.sourceFrame Actual Result (lldb) po navigationAction.sourceFrame nil Swift declaration lies: public var sourceFrame: WKFrameInfo { get } // non-optional → Instant EXC_BREAKPOINT libswiftFoundation.dylib`URLRequest._unconditionallyBridgeFromObjectiveC Objective-C tells the truth: po [(WKNavigationAction *)navigationAction fixedSourceFrame] nil iOS 18.6 → same code prints a valid WKFrameInfo, no crash. Expected sourceFrame must be declared WKFrameInfo? in Swift or at least documented “can be nil on iOS 15–16”. Impact Every WKWebView app that touches sourceFrame on iOS 15.4 & 16.6 ships with a latent crash. Production Workaround @implementation WKNavigationAction (Safe) (WKFrameInfo *)fixedSourceFrame { return self.sourceFrame ? self.sourceFrame : nil; } @end Minimal Test (copy-paste) import UIKit import WebKit class ViewController: UIViewController, WKNavigationDelegate { lazy var web = WKWebView(frame: view.bounds) override func viewDidLoad() { super.viewDidLoad() web.navigationDelegate = self view.addSubview(web) web.load(URLRequest(url: URL(string: "https://www.apple.com")!)) } func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, preferences: WKWebpagePreferences, decisionHandler: @escaping (WKNavigationActionPolicy, WKWebpagePreferences)->Void) { print(navigationAction.sourceFrame) // ← crashes on 15.4 & 16.6 decisionHandler(.allow, preferences) } }
Topic: Safari & Web SubTopic: General Tags:
3
0
778
Nov ’25