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

All subtopics
Posts under Safari & Web topic

Post

Replies

Boosts

Views

Activity

Smart App Banner not appearing
I'm trying to set up a smart app banner for my app, but it doesn't appear on the website when I try to test it. I have the meta tag on my website: <meta name="apple-itunes-app" content="app-id=6740216045" /> When I inspect the website, I can see that the meta tag is showing up in the head, but the banner is nowhere to be found. I tried clearing website data but still no dice.
0
0
283
Jan ’25
Unable to Open HTTP Site B from HTTP Site A in WKWebView – Stuck on Spinning Wheel (Xcode 15.2 and above, VPN Enabled, Cross-Domain)
After upgrading to Xcode 15.2 or above(Till Xcode 16.2), users are unable to open Site B (HTTP URL) from Site A (HTTP URL) within our Browser app when loaded in WKWebView. Clicking the link to Site B results in a spinning wheel, but the site does not load. This issue is not present when the app is built with Xcode 15.0.1. Additionally: Users are connected to a VPN, which is required to access the sites. Site A and Site B are on different domains (cross-domain request). Expected Behavior: Clicking the link to Site B should successfully load the site with user information passed from Site A. Current Behavior: Clicking the link results in a spinning wheel, but Site B does not load inside WKWebView. Technical Details: Both Site A and Site B use HTTP (not HTTPS). Site A and Site B have different domains (cross-domain request). Do not use location.href for transitions. Instead, we temporarily set about:blank in an iframe and then submit data via a form to the target system’s URL within the iframe. This approach worked in Xcode 15.0.1 but fails in Xcode 15.2 or above. Users are connected to a VPN, which is required to access the sites. WKWebview is not receiving navigation delegate callback for Site B Steps to Reproduce: Ensure the device is connected to a VPN. Open the app (using WKWebView) built with Xcode 15.2 or above. Load Site A (HTTP) within the app in WKWebView. Click the link to Site B (HTTP), which should open in an iframe. Observe that a spinning wheel appears, but Site B does not load. Environment: Xcode Versions Affected: 15.2 or above (issue present), 15.0.1 (no issue) iOS Version: All iOS versions Devices: iPad Questions: Has there been any change in WKWebView’s handling of HTTP URLs or VPN-related network traffic in Xcode 15.2? Are there any new security policies, iframe restrictions, or VPN-related changes in this version that might be affecting this behavior? Request for Assistance: Can you confirm if this is a known issue or an intended change? Are there any workarounds available?
Topic: Safari & Web SubTopic: General Tags:
1
0
103
Mar ’25
Safari Takes 30 Seconds to Load mTLS-Enabled Sites Unless in Private Browsing
I’m experiencing an issue where Safari takes approximately 30 seconds to load web pages on mTLS-enabled sites. However, when I enable Private Browsing mode, the problem disappears. This suggests that the issue is not related to the network environment. To provide more context, I’ve attached a Wireshark packet capture for reference. From the logs, it seems that the TLS handshake process encounters delays, but I cannot identify the exact cause. Has anyone encountered a similar issue or can provide insights into what might be causing this behavior? Any troubleshooting suggestions or fixes would be greatly appreciated. OS: iPadOS 18.2.1 Thank you! Wireshark packet capture
Topic: Safari & Web SubTopic: General
0
0
205
Jan ’25
Detecting tabs change in Safari App Extension when switching windows inside validateToolbarItem.
Hi. I'm a developer of Tab Finder (https://apps.apple.com/us/app/tab-finder/id6741719894) My problem is that every time i switch from my first window to a second window, the tabs in the validateToolbarItem() are INcorrect on a first call, but when I switch back from the second window to my main window, the tabs are CORRECT even on a first call. To demonstrate it, i recorded a video: https://youtu.be/RwskzrSJ8u0 To run the same sample extension from the video, you can get the code from this GitHub repo: https://github.com/kopyl/test-tabs-change Its only purpose is to log URLs of an active page of all tabs. The SafariExtensionHandler's code of the sample app is very simple: import SafariServices func printOpenTabsHost(in window: SFSafariWindow) async { let tabs = await window.allTabs() log("Logging tabs for a new window: \(window.hashValue)") for tab in tabs { let page = await tab.activePage() let properties = await page?.properties() let url = properties?.url log(url?.absoluteString ?? "No URL") } } class SafariExtensionViewController: SFSafariExtensionViewController { static let shared = SafariExtensionViewController() } class SafariExtensionHandler: SFSafariExtensionHandler { override func validateToolbarItem(in window: SFSafariWindow, validationHandler: @escaping ((Bool, String) -> Void)) { Task { await printOpenTabsHost(in: window) } validationHandler(true, "") } override func popoverViewController() -> SFSafariExtensionViewController { return SafariExtensionViewController.shared } } Could you please tell if i'm missing something and how to see the actual tabs inside the overridden validateToolbarItem call of the SafariExtensionHandler (or in any other way, I'm okay with any implementation as long as it works).
0
0
367
Mar ’25
macOS customized shortcut for Safari with menu title "ReTab" doesn't trigger the extension
Hello! I've made a Safari extension that supports command "ReTab", and a couple of month ago, adding a customized macOS shortcut for Safari with menu title "ReTab" did trigger the extension. However, it's not working anymore and I'm not sure if it's from macOS/Safari update or because I changed manifest from v2 to v3 - could you help check if there's anything wrong with either the manifest.json or background.js? (the default Cmd+E still works) Thank you in advance! Xun manifest.json: { "manifest_version": 3, "default_locale": "en", "name": "ReTab", "description": "Go to the last active tab with Cmd+E!", "version": "1.4", "homepage_url": "https://LycheeIsle.com", "background": { "service_worker": "background.js" }, "action": { "default_icon": "images/toolbar-icon.svg" }, "permissions": [ "commands", "tabs", "storage" ], "commands": { "ReTab": { "suggested_key": { "default": "Command+E" }, "description": "Go to the last active tab" } }, "options_page": "options.html" } in background.js, I have this line which should listen to the command, and Cmd+E works but any customized shortcut for "ReTab" in Safari doesn't: browser.commands.onCommand.addListener(async (command) => { if (command === "ReTab" || command === "retab") { await retab() } });
1
0
356
Feb ’25
I have a Swift binary helper that works as a native messaging host for Chrome, Edge, and Firefox using stdin/stdout. I want to use the same binary for a Safari Web Extension as well.
Since Safari requires a macOS app as a container for Web Extensions, is there a way to establish native messaging directly from SafariWebExtensionHandler using stdin/stdout? Or does Safari enforce a different communication mechanism? I’d like to keep the same approach as other browsers. Any guidance on making this work would be appreciated!
2
0
82
Mar ’25
Push subscribe error User denied push permission
Hi, I am developing the Click & Read web add-on for Chromium, Firefox and Safari. We use xcrun safari-web-extension-converter tool to generate the Safari add-on, with up-to-date MacBook MacOS, Xcode et Safari : Sequoia 15.3.2, Safari Version 18.3.1 (20620.2.4.11.6), XCode Version 16.0 (16A242d). We have updated our addon to Manifest v3, having the Background script as Server Worker "background": { "service_worker": "background.js", "type": "module" } self.addEventListener("activate", (event) => { console.info("Service Worker activated", event); event.waitUntil( self.registration.pushManager .subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array( process.env.VAPID_PUBLIC_KEY ), }) .then(async (subscription) => { console.info("[Service Worker] Extension is subscribed to push"); const { subscription: savedSubscription } = await getLocalStorageKeyData("subscription"); if (savedSubscription) fetchApi({ url: `${API_SERVER_URL}/subscription/remove/${savedSubscription.keys.auth}`, }); // Remove previous subscription from server on addon activate currentBrowser.storage.local.set({ subscription: subscription.toJSON(), }); // Save subscription in local storage currentBrowser.runtime.setUninstallURL( `${API_SERVER_URL}/subscription/remove/${ subscription.toJSON().keys.auth }` ); // Set uninstall URL to remove notification subscription on addon uninstall fetchApi({ url: `${API_SERVER_URL}/subscription`, reqInit: { body: JSON.stringify(subscription.toJSON()), method: "POST", headers: { "Content-Type": "application/json", }, }, }); }) .catch((error) => { console.error("Push subscribe error: ", error); }) // Subscribe to push notifications ); }); When trying to subscribe the addon instance to our Push server, we get this error : Push subscribe error: NotAllowedError: User denied push permission Our NodeJS backend is using the web-push librabry : https://github.com/web-push-libs/web-push) to save subscriptions and make notifications push. By looking for same errors on forums, the best hint I found is that it could be related to the testing is done on localhost (addon is built from XCode onto Safari, and Push server is running on localhost). Thanks for your help !
1
0
357
Mar ’25
Service Worker Registration Requires WKAppBoundDomains – Any Workarounds?
"We have a multi-tenant EdTech platform serving over 1500 clients, each with a unique domain (e.g., client1.eduapp.com). We use WKWebView in a native shell. Due to WKAppBoundDomains restriction, we can't dynamically list all domains. How can we support dynamic tenants while maintaining cookie persistence" "Can Apple suggest a best practice or alternative approach for apps using WebView/PWA shell architecture across multiple client domains?" Problem: We cannot predefine all 1500 domains in WKAppBoundDomains due to limitations. As a result: Service workers fail to register, breaking PWA functionality Ex: Offline.
Topic: Safari & Web SubTopic: General
0
0
70
Apr ’25
TestFlight deeplink
I can open an app (e.g. tiktok) from a website of mine by using the deeplink “tiktok://open”, if the app is installed on my iphone. What's the deeplink to launch TestFlight? Thanks in advance
Topic: Safari & Web SubTopic: General
1
0
198
Apr ’25
Help with Device Orientation Permission on iPhone (iOS 18) in Safari
Hi everyone, I'm facing an issue with accessing device orientation and motion events in Safari on my iPhone (iOS 18). Despite trying several guides and solutions, I cannot find the option to allow access to motion and orientation for websites in the browser settings. I’ve checked privacy settings, and the device is up to date. Can anyone guide me on how to enable this feature in Safari or share any workarounds? Thanks in advance!
0
0
627
Dec ’24
Apple Pay on the Web fails with an "AbortError" in production
Apple Pay fails with an "AbortError" when the dialog for the fingerprint sensor opens. How do I find the cause of the "AbortError" which only occurs in the web integration in our production environment? In the sandbox environment, Apple Pay works flawlessly. This concerns a web integration of Apple Pay using the Apple Pay SDK, one version before 1.2.0. The error occurs when I call the show() method on the PaymentRequest object. The Apple Pay dialog opens with the fingerprint icon, but after one second, an exclamation mark appears, and the Apple Pay dialog closes again while throwing the "AbortError". I know that our Apple Pay integration worked for multiple customers in the production environment already. The current problem is that Apple's error message, called "AbortError," provides no indication of the cause. This could be greatly improved. One affected customer, for example, is the one with the Merchant ID … (Is it safe to post a Merchant ID in this forum?) I can reproduce the "AbortError" issue at any time using my iPhone with iOS 16.7.8.
0
0
383
Jan ’25
Please Help: WKwebview not allowing background audio playback
I’ve been working on a personal iOS project for fun — essentially a YouTube music player, learning how background media playback works in native iOS apps. After seeing that Musi (a famous music streaming app) can play YouTube audio in the background with the screen off — I got really curious. I’ve been trying to replicate that basic background audio functionality for YouTube embeds using WKWebView. I've spent a crazy amount of time (probably 20 hours) trying to figure this out but have achieved no success. Here’s what I’ve tried so far: -Embedding a YouTube video in a WKWebView -Activating AVAudioSession with .playback and setting .setActive(true) -Adding the UIBackgroundModes key with audio in Info.plist -Adding the NSAppTransportSecurity key to allow arbitrary loads --Testing on a real device (iPhone 14, iOS 18.1 target)-- What happens: Audio plays fine in the foreground. If I exit the app and go to the lock screen quickly enough (less than 3 seconds) after pressing play, I can resume playback briefly from the lock screen — but it doesn’t automatically continue like in Musi and other apps like it. Most of the time, the audio stops when the app is backgrounded. I get this error consistently in the logs: Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple.runningboard.assertions.webkit AND originator doesn't have entitlement com.apple.multitasking.systemappassertions)" It seems like the app lacks some specific entitlements related to WebKit media playback. I don’t have AppDelegate/SceneDelegate (using SwiftUI), but can add if needed. I’m super curious how music streaming apps using youtube as a source get around this — are they doing something different under the hood? A custom player? A SafariViewController trick? Is there a specific way to configure WKWebView to keep playing in the background, or is this a known limitation? Would really appreciate any insight from folks who’ve explored this before or know how apps like Musi pulled it off. Thanks in advance!
0
0
126
Apr ’25
HELP!Apple Pay Web application cannot pay due to the bottom rotation issue
I built a web application using the Apple Pay on the Web Interactive Demo with the Payment Request API, but encountered a few issues: The initiated web Apple Pay interface shows a spinning circle at the bottom and cannot proceed with payment(Bottom display:正在处理). What could be causing this? How to set up sandbox testing for payments? How to asynchronously and synchronously retrieve payment results (backend code to fetch payment results)? The demo only shows frontend code using await response.complete("success"); for retrieving payment results my demo URL: https://shop.wowseer.com/rsolomakhin/pr/applepay/
0
0
86
Apr ’25
Issue with Declarative Net Request Rule (DNR) Persistence Across Redirects in Safari
When a DNR rule is set for a specific URL and the request receives a server-side redirect (e.g., 302) to a different URL that does not match the urlFilter, the rule still seems to apply to the redirected request. We are using macOS 15.4 and Safari 18.4. For example, consider two sequential calls: call1 and call2. call1 triggers a 302 redirect to call2. A DNR rule is created to add a "Cookie" header to call1 based on its URL. Unexpectedly, the same cookie is also added to call2, even though call2's URL does not match the rule's urlFilter. This results in the Set-Cookie response from call1 being ignored, and call2 receiving the manually set cookie instead—leading to incorrect behavior. This issue doesn't occur in Chrome or Firefox, where the rule is not applied to the redirected request if the URL no longer matches. We are looking for assistance in fixing these issues and having our Safari Extension function the same as it does in Firefox and Chrome.
0
0
110
Apr ’25
App crashed when click the selected content on HTML with custom font-family
Crash Stack: thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BREAKPOINT (code=1, subcode=0x19ba3bb04) frame #0: 0x000000019ba3bb04 CoreFoundation`forwarding.cold.2 + 92 frame #1: 0x000000019b8ab718 CoreFoundation`forwarding + 1288 frame #2: 0x000000019b8ab150 CoreFoundation`_CF_forwarding_prep_0 + 96 frame #3: 0x000000019df230b0 CoreText`TCFRef<CTRun*>::Retain(void const*) + 40 frame #4: 0x000000019e052050 CoreText`CreateFontWithFontURL(__CFURL const*, __CFString const*, __CFString const*) + 476 frame #5: 0x000000019e052874 CoreText`TCGFontCache::CopyFont(__CFURL const*, __CFString const*, __CFString const*) + 144 frame #6: 0x000000019df27dcc CoreText`TBaseFont::CopyNativeFont() const + 232 frame #7: 0x000000019df8ee64 CoreText`TBaseFont::GetInitializedGraphicsFont() const + 152 frame #8: 0x000000019df26d70 CoreText`TBaseFont::CopyVariationAxes() const + 296 frame #9: 0x000000019df2d148 CoreText`TDescriptor::InitBaseFont(unsigned long, double) + 768 frame #10: 0x000000019df21358 CoreText`TDescriptor::CreateMatchingDescriptor(__CFSet const*, double, unsigned long) const + 604 frame #11: 0x000000019df251f8 CoreText`CTFontCreateWithFontDescriptor + 68 frame #12: 0x00000001bff8dfb8 WebCore`WebCore::createCTFont(__CFDictionary const*, float, unsigned int, __CFString const*, __CFString const*) + 124 frame #13: 0x00000001bff8e8bc WebCore`WebCore::FontPlatformData::fromIPCData(float, WebCore::FontOrientation&&, WebCore::FontWidthVariant&&, WebCore::TextRenderingMode&&, bool, bool, std::__1::variant<WebCore::FontPlatformSerializedData, WebCore::FontPlatformSerializedCreationData>&&) + 228 frame #14: 0x00000001c128eef4 WebKit`IPC::ArgumentCoder<WebCore::Font, void>::decode(IPC::Decoder&) + 1352 frame #15: 0x00000001c1333ca4 WebKit`std::__1::optional<WTF::HashMap<WTF::String, WebCore::AttributedString::AttributeValue, WTF::DefaultHashWTF::String, WTF::HashTraitsWTF::String, WTF::HashTraitsWebCore::AttributedString::AttributeValue, WTF::HashTableTraits>> IPC::ArgumentCoder<WTF::HashMap<WTF::String, WebCore::AttributedString::AttributeValue, WTF::DefaultHashWTF::String, WTF::HashTraitsWTF::String, WTF::HashTraitsWebCore::AttributedString::AttributeValue, WTF::HashTableTraits>, void>::decodeIPC::Decoder(IPC::Decoder&) + 480 frame #16: 0x00000001c1333a5c WebKit`std::__1::optional<WTF::HashMap<WTF::String, WebCore::AttributedString::AttributeValue, WTF::DefaultHashWTF::String, WTF::HashTraitsWTF::String, WTF::HashTraitsWebCore::AttributedString::AttributeValue, WTF::HashTableTraits>> IPC::Decoder::decode<WTF::HashMap<WTF::String, WebCore::AttributedString::AttributeValue, WTF::DefaultHashWTF::String, WTF::HashTraitsWTF::String, WTF::HashTraitsWebCore::AttributedString::AttributeValue, WTF::HashTableTraits>>() + 28 frame #17: 0x00000001c1333804 WebKit`std::__1::optional<std::__1::pair<WebCore::AttributedString::Range, WTF::HashMap<WTF::String, WebCore::AttributedString::AttributeValue, WTF::DefaultHashWTF::String, WTF::HashTraitsWTF::String, WTF::HashTraitsWebCore::AttributedString::AttributeValue, WTF::HashTableTraits>>> IPC::Decoder::decode<std::__1::pair<WebCore::AttributedString::Range, WTF::HashMap<WTF::String, WebCore::AttributedString::AttributeValue, WTF::DefaultHashWTF::String, WTF::HashTraitsWTF::String, WTF::HashTraitsWebCore::AttributedString::AttributeValue, WTF::HashTableTraits>>>() + 156 frame #18: 0x00000001c121f368 WebKit`IPC::ArgumentCoder<WebCore::AttributedString, void>::decode(IPC::Decoder&) + 172 frame #19: 0x00000001c121f124 WebKit`std::__1::optionalWebCore::AttributedString IPC::Decoder::decodeWebCore::AttributedString() + 28 frame #20: 0x00000001c12594ec WebKit`IPC::ArgumentCoder<WebCore::DictionaryPopupInfo, void>::decode(IPC::Decoder&) + 76 frame #21: 0x00000001c12d0660 WebKit`std::__1::optionalWebCore::DictionaryPopupInfo IPC::Decoder::decodeWebCore::DictionaryPopupInfo() + 28 frame #22: 0x00000001c12ceef0 WebKit`IPC::ArgumentCoder<WebKit::WebHitTestResultData, void>::decode(IPC::Decoder&) + 1292 frame #23: 0x00000001c1338950 WebKit`std::__1::optionalWebKit::WebHitTestResultData IPC::Decoder::decodeWebKit::WebHitTestResultData() + 28 frame #24: 0x00000001c1ec7edc WebKit`WebKit::WebPageProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 31392 frame #25: 0x00000001c1fb8f28 WebKit`IPC::MessageReceiverMap::dispatchMessage(IPC::Connection&, IPC::Decoder&) + 272 frame #26: 0x00000001c19ab2c0 WebKit`WebKit::WebProcessProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 44 frame #27: 0x00000001c1fb3254 WebKit`IPC::Connection::dispatchMessage(WTF::UniqueRefIPC::Decoder) + 252 frame #28: 0x00000001c1fb3768 WebKit`IPC::Connection::dispatchIncomingMessages() + 576 frame #29: 0x00000001b9ab90c4 JavaScriptCore`WTF::RunLoop::performWork() + 204 frame #30: 0x00000001b9ab9fec JavaScriptCore`WTF::RunLoop::performWork(void*) + 36 frame #31: 0x000000019b8cc8a4 CoreFoundation`CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 28 frame #32: 0x000000019b8cc838 CoreFoundation`__CFRunLoopDoSource0 + 176 frame #33: 0x000000019b8cc59c CoreFoundation`__CFRunLoopDoSources0 + 244 frame #34: 0x000000019b8cb138 CoreFoundation`__CFRunLoopRun + 840 frame #35: 0x000000019b8ca734 CoreFoundation`CFRunLoopRunSpecific + 588 frame #36: 0x00000001a6e39530 HIToolbox`RunCurrentEventLoopInMode + 292 frame #37: 0x00000001a6e3f348 HIToolbox`ReceiveNextEventCommon + 676 frame #38: 0x00000001a6e3f508 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 76 frame #39: 0x000000019f442848 AppKit`_DPSNextEvent + 660 frame #40: 0x000000019fda8c24 AppKit`-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 688 frame #41: 0x000000019f435874 AppKit`-[NSApplication run] + 480 frame #42: 0x000000019f40c068 AppKit`NSApplicationMain + 888 frame #43: 0x00000001ca56a70c SwiftUI`merged generic specialization <SwiftUI.TestingAppDelegate> of function signature specialization <Arg[0] = Existential To Protocol Constrained Generic> of SwiftUI.runApp(__C.NSResponder & __C.NSApplicationDelegate) -> Swift.Never + 160 frame #44: 0x00000001ca9e09a0 SwiftUI`SwiftUI.runApp<τ_0_0 where τ_0_0: SwiftUI.App>(τ_0_0) -> Swift.Never + 140 frame #45: 0x00000001cad5ce68 SwiftUI`static SwiftUI.App.main() -> () + 224 frame #46: 0x0000000105943104 MyApp Dev.debug.dylib`static MyMacApp.$main() at :0 frame #47: 0x0000000105943c9c MyApp Dev.debug.dylib`main at MyMacApp.swift:24:8 frame #48: 0x000000019b464274 dyld`start + 2840
1
0
168
May ’25
Apple Pay Third party browsers - completeMerchantValidation fails
I've a apple pay integration on my website. The new sdk, that allows third party browsers. My integration works well everywhere, except on third party when I read the QR code it results in a "payment incomplete". I have gone through several threads in apple dev forums, and several guides on implementation steps and troubleshooting. But I'm still without solution. When Debugging in iOS device I get: "Application failed to provide a valid merchant session. We can't proceed to authorize the transaction." I've doublechecked, the values I send to create the payment Session are correct, the domain and merchantIds. (It works well with the same implementation on safari, what's the difference here?) I've also doublechecked the values i'm sending to the completeMerchantValidation, and they are all in the right format and types. What else can iIcheck?
0
0
368
Feb ’25