WKWebview of iOS 18 includes Safari browser. When playing videos, some videos show "NotSupportedError: The operation is not supported.", but it is normal on iOS15 devices. The video link is as follows. Even if it is downloaded and referenced locally in HTML, it cannot be played, so it is ruled out that it is a network problem.
https://ydtj-adas.oss-cn-shanghai.aliyuncs.com/e6yun.com/exam/exam/a35447b496b94e5e9a6aab27d62c867e.mp4 cannot be played
https://ydtj-adas.oss-cn-shanghai.aliyuncs.com/e6yun.com/exam/exam/82d970957a7d4e8d88c13cd101143005.mp4 can be played
Explore the integration of web technologies within your app. Discuss building web-based apps, leveraging Safari functionalities, and integrating with web services.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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?
Hi!
I'm working on a web extension for Safari and I need to send messages from the containing application to JavaScript. For this I use the method
class func dispatchMessage(
withName messageName: String,
toExtensionWithIdentifier identifier: String,
userInfo: [String : Any]? = nil
) async throws
of the SFSafariApplication class. If the site is opened in Safari in normal mode, everything works as expected. However, if the site is "docked", the messages are not transmitted to this "Web App".
I tried to create a content blocker for Safari and did it through Safari App Extension and Safari Web Extension.
The XCode project for Safari Extension creates 2 applications: the “Main Application” (which is compiled into ".app") and the “Safari Extension” itself (which is compiled into ".appex").
If you want to create a content blocker, you must add “Content Blocker Extension” from the “File → New → Target” menu. This will be the third application in the group, which is also compiled into "*.appex".
And now about differences...
The first difference is that Web Extension does not have the right to work on any domains by default, unlike App Extension. For the App Extension, in the "info.plist" in the "SFSafariWebsiteAccess" section, we can remove "Allowed Domains" and in "Level" replace "Some" to "All". This is important because the content blocker should work on any domain, and not be turned on manually for each individual. This will not work in Web Extension and will have to be activated for each domain separately.
The second significant difference between Web Extension and App Extension is that for security reasons it is more limited in page management.
Web Extensions are supposedly focused on a common API for all browsers (Firefox, Chrome, Opera, Edge, Safari), but if I use Safari and want maximum integration with it, then I don't care about all those browsers. In this case, I don't need Web Extension.
App Extension functions as a client-server even within the “Main Application”. This is quite expensive and can be fixed. You can remove the “webView” component from storyBoard and remove this files: “script.js”, “main.html”, “style.css”. After this you will get the pure storyBoard without any tinsel and communication between these layers. That’s will work perfectly because these are native Swift applications.
p.s. To show the "Safari Extension" window after clicking on the icon on the toolbar, you need to change key from "Command" to "Popover" in the "info.plist" in the section "SFSafariToolbarItem" in the "Action".
write your additions...
Topic:
Safari & Web
SubTopic:
General
Hello, following problems described here:
https://developer.apple.com/forums/thread/765272
Last version of Safari apparently corrected previous bugs, however we encountered another problem. Right now Safari uses autocomplete feature of some kind (Siri suggested websites/Top hit) which triggers blocking while writing the name of the website. Probably somehow loads website in the background. Problem is, that this behavior is impossible to debug, because this autocomplete doesn't work, while the browser console is open. We are using content script for blocking.
Please advise.
Thanks very much
Topic:
Safari & Web
SubTopic:
General
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
Hi all!
I have been working on a web speech recognition service using the Web Speech API. This service is intended to work on smartphones, primarily Chrome on Android and Safari (or WebKit WebView) on iOS.
In my specific use case, I need to set the properties continuous = true and interimResults = true. However, I have noticed that interimResults = true does not always work as expected in WebKit.
I understand that this setting should provide fast, native, on-device speech recognition with isFinal = false. However, at times, the recognition becomes throttled and slow, yielding isFinal = true and switching to cloud-based recognition.
To confirm whether the recognition is cloud-based, I tested it by disabling the internet connection before starting speech recognition. In some cases, recognition fails entirely, which suggests that requiresOnDeviceRecognition = false is being applied. (Reference: SFSpeechRecognitionRequest.requiresOnDeviceRecognition)
I believe this is not the expected behavior when setting interimResults = true. I have researched the native services used by the Web Speech API on iOS devices, and the following links seem relevant:
• SFSpeechRecognizer
• SFSpeechRecognitionRequest.shouldReportPartialResults
• SFSpeechRecognizer.supportsOnDeviceRecognition
• Recognizing speech in live audio
• Apple Developer Forums Discussion
I found that setRequiresOnDeviceRecognition and setShouldReportPartialResults appear to be set correctly, but apparently, they do not work as expected:
WebKit Source Code
We are building a Safari web extension utilising native messaging, to send messages to the Swift native part of the app. We sometimes experience, that the beginRequest handler is executed multiple times, at the same time.
We have a special part of the code in the handler, that must be run only once. Because it uses NS defaults storage, and also because it calls our servers. We have tried to use a serial dispatch queue, as well as other locking and mutex techniques, to no success.
We suspect that the instances of the handler are isolated in a way, that these locks don’t work (maybe they don’t share memory?). But we are not sure. When looking at os_logs from the handlers, they all share the same PID.
Has anyone experienced anything similar and can shed some light on what's going on?
I am trying to build and run a Safari Web Extension from Xcode and I have enabled "Allow unsigned extensions" in Safari settings. However, I see the below pop up:
And, if click on the "Quit and Open Safari Extensions Preferences..." button, the project stops running on Xcode and nothing happens.
What can be the issue? The extension works and runs fine if I get it from the Mac App Store and this only happens when running from Xcode. I even tried completely uninstalling the mac app store version and still facing the same issue.
I'm posting a question here as I have encountered an issue while seeking help from engineers in the thread. thread773837
If the "Not Secure Connection Warnings" is enabled in Settings > App > Safari, are HTTP connections not allowed under any circumstances?
I also posted a question about NSAllowsLocalNetworking not being applied, and I was informed that ATS (App Transport Security) is not related to SFSafariViewController. If that's the case, what feature causes the error "Safari cannot open the page. Error: Failed to navigate to an HTTP URL with HTTPS-only mode enabled"?
I am currently working to resolve this issue.
We have noticed that in iOS 16 or greater , the Smart App Banner which shows based on meta tag added is not showing the app ratings inside the popup. Can we override this new behavior to show ratings and custom text.
Hi!
My SwiftUI app is a rather complex browser app. Starting with iOS 18, the app crashes due to repeted reloads of the WkWebView. I’ve tracked the issue as far as I can, but I still haven’t found the root cause.
My app is structured like this:
MainView holds a cuple of subviews. It also holds a @StateObject called viewModel that holds a lot of @Published vars. The viewModel is passed as a enivormentObject.
Example from ViewModel:
@MainActor class ViewModel: NSObject, ObservableObject {
@Published public var isLoading: Bool = false
@Published public var loadProgress: Double? = 0
public func setIsLoading(_ value: Bool) async {
self.isLoading = value
}
public func setLoadProgress(_ value: Double?) async {
self.loadProgress = value
}
}
WebView is a subview of MainView, which holds a navigation bar, and a UIViewRepresentable, which is a WkWebView.
The WkWebView pushes some states to the ViewModel as the underlying values of the WkWebView changes, i.e. estimaedProgress, and isLoading. This is done via KVO and works like this:
estimatedProgressObservation = self.parent.webView.observe(\.estimatedProgress) { webView, progress in
Task {
await parent.viewModel.setLoadProgress(webView.estimatedProgress)
}
}
isLoadingObservation = self.parent.webView.observe(\.isLoading) { webView, value in
Task {
await parent.viewModel.setIsLoading(webView.isLoading)
}
}
By using a timer in WkWebViews Coordinator, i trigger a load after a configurable amount of time :
func loadUrl(url: URL) {
DispatchQueue.main.async {
console.info("Load URL: ...", sensitive: "Load URL: \(url.absoluteString)")
let policy: NSURLRequest.CachePolicy
if self.parent.settings.noCache {
policy = .reloadIgnoringLocalAndRemoteCacheData
} else {
policy = .useProtocolCachePolicy
}
let request = URLRequest(url: url, cachePolicy: policy)
self.parent.webView.load(request)
}
}
Running the app with the automatic reload enabled freezes the app after a couple of hours. It also seems to freeze Safari on the device. The device needs to be rebooted.
If I inspect the device's running processes, hundreds of ”com.apple.webkit. web content " processes are running.
Removing await parent.viewModel.setLoadProgress(webView.estimatedProgress) and await parent.viewModel.setIsLoading(webView.isLoading) fixes the issue, but it is necessary for other app functions. Therefore, is suspect that the viewModel somehow causes the bug.
The issue arises after a couple of loads 5-10. The debugger shows a message when the processes start to pile up. I suspect its related.
Failed to terminate process: Error Domain=com.apple.extensionKit.errorDomain Code=18 "(null)" UserInfo={NSUnderlyingError=0x12d0e7f60 {Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.terminateprocess, NSLocalizedFailureReason=Client not entitled, RBSPermanent=true}}}
How can I find out what causes the suspected memory leak? Instruments gives me nothing of value. The memory leak wasn't present in iOS 17. Is this a bug in iOS 18, or was something intentionally changed?
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.
Apple must comply with the requirements of the Level Index, the global digital credit gateway, and suspend gift cards and similar services until formal arrangements are made with service providers.
Howdy,
WKWebView feature request: allow Fullscreen API without User Gestures
similar to ElectronJS' userGesture: true flag that allows devs to bypass user gesture restriction for Fullscreen API and similar
executeJavaScript(code[, userGesture])
https://www.electronjs.org/docs/latest/api/web-contents#contentsexecutejavascriptcode-usergesture
afaik this is allowed because of a fairly recent update to Chromium that also allows users to give Fullscreen API permissions per domain
https://chromeos.dev/en/posts/using-the-fullscreen-api-without-gestures
Would be greatly useful for a use case in my cross-platform app, so I can avoid rewriting all platforms to use Chromium
Thanks
Hi everyone,
We're building a web application using Next.js that captures around 40 images across different routes as part of a guided user flow.
At the beginning of the process, we explicitly request camera permission using navigator.mediaDevices.getUserMedia(...), and the user grants it successfully.
However, as users proceed through the flow (navigating between routes), Safari on iOS intermittently re-prompts for camera access—despite the initial permission already being granted and the origin (domain) remaining unchanged.
This repeated prompting interrupts the user experience significantly.
What we’ve tried:
Ensuring camera access is requested only once and reused where possible.
Using persistent media stream across routes (where feasible).
Testing across different iOS versions to confirm consistency.
Questions:
Is there a known workaround or best practice to persist camera access across route transitions in a SPA/PWA context on iOS?
Are there any Safari-specific behaviors or restrictions related to WebRTC / getUserMedia we should be aware of?
Would embedding the camera view in an iframe or maintaining a persistent component help avoid re-prompting?
Any guidance or shared experience would be greatly appreciated.
Thanks in advance!
Topic:
Safari & Web
SubTopic:
General
There is no problem with the content display of each tab, but the tab bar is completely buggy.
If you open 5 or more tabs and browse tabs after the 5, the first 4 tab bars will be completely blacked out, and you don't even know how many tabs you have.
If you click on the place where the tab title probably exists, the tab is displayed as if the partial display of the tab bar has been restored.
There is no problem with content display. But because it is unclear what tab is open, the browsing experience is at its lowest.
If you switch to the tab after the 5th, the first 4 will return to the blackout state again.
Of course, it is the latest software configuration at the moment. There is no shortage of memory at 24GB.
I recently started developing a Safari extension with AppExtension, but is that due to it?
Topic:
Safari & Web
SubTopic:
General
We have written a PAC script that blocklists certain domains and whitelists others. We went to Settings > Network > Wi-Fi (the network we are using), then clicked on Details, and under Proxies, we added the PAC file URL in the Automatic Proxy Configuration section.
We tried hosting the PAC file both on localhost and on a separate HTTP server.
After saving the settings, we tested several URLs. The blocking and allowing behavior works correctly in all browsers except Safari.
Below is the PAC script we are using for your reference.
The script works as expected in browsers other than Safari.
This is how the PAC script URL looks:
http://localhost:31290/proxy.pac
function FindProxyForURL(url, host) {
var blacklist = new Set(["facebook.com", "deepseek.com"]);
var b_list = [...blacklist];
for (let i = 0; i < b_list.length; i++) {
let ele = b_list[i] + "*";
if (shExpMatch(host, ele) || shExpMatch(url, ele)) {
return "PROXY localhost:8086";
}
}
if (isIPBlocked(whitelist_subnet, hostIP)) {
return "PROXY localhost:8087";
}
if (isIPBlocked(blacklist_subnet, hostIP)) {
return "PROXY localhost:8086";
}
return "PROXY localhost:8080";
}
When our Safari Web Extension makes a api request from its background script (registered via "scripts" in manifest.json, e.g., "background": { "scripts": ["js/background.bundle.js"] }) to our authenticated API endpoint (https://api-domain/user), the Cookie header is not included in the request. This occurs only when the extension is running within a non-default Safari User Profile. This causes our API to treat the user as unauthenticated. The exact same extension code, manifest, and API call work correctly (Cookie header is present and user is authenticated) when the extension is running in the Default Safari User Profile.
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 !