Since iOS 18.1 launched as a beta, we've been getting reports from end users on iPhone 15 Pro and iPhone 15 Pro Max specifically. They're reporting that our WebView is unable to load our local HTML content. I'm curious if anyone else has had their app or users run into this issue?
So far I've tried installing the most recent XCode Beta 16B5014f and installed an 18.1 emulator, but our app worked fine. It's also working fine on all my real devices, but we don't have a 15 Pro to test on. I'm curious if this is related to the processor on these devices and how they are intended to support Apple's new AI coming in 18.1.
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
I’m developing a Safari App Extension and I want to debug the background.js script.
However, I can’t find any tool or option to do this.
When I run the extension from Xcode using the ProjectName Extension (macOS) scheme, I expect to see a “ProjectName” item under the Develop → Web Extension Background Content menu.
But there’s nothing there.
Has anyone encountered the same issue? How did you fix it?
Environment:
Manifest Version: V3
Safari: 26.0.1 (21622.1.22.11.15)
Xcode: 26.0.1 (17A400)
There does not appear to be any way to use or create iCloud passkeys with a Safari Web Extension, either using the navigator.credentials API in an extension origin webpage such as the popover, or using the AuthenticationServices framework in the SafariWebExtensionHandler.
I've setup an associated domain for my plugin, and I know it works for the host application. But I get errors trying to do so in the web extension target.
createCredentialRegistrationRequests results in the following error:
Domain=com.apple.AuthenticationServices.AuthorizationError Code=1004 "Application with identifier <ID> is not associated with domain <RPID>
The other problem, assuming the entitlement works correctly for the web extension, is that there is no NSWindow to use as the presentation target from the SafariWebExtensionHandler.
Trying to use the navigator.credentials.create JS API (which is the preferred method, frankly, in a web extension) results in the following error:
NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
Chrome has a great solution for this that I believe should be adopted by Safari. If an extension has host permissions for a relying party it wants to claim, or if it has an associated domain entitlement for it, webauthn operations should be allowed.
I'm working on a Safari web extension that uses the nativeMessaging facility to communication with native code.
When I want to notify the javascript extension from the embedding application, I use SFSafariApplication::dispatchMessage. As per the documentation, this call
... ensures that Safari is launched and that your extension is running before delivering the message.
Everything works fine when the background script is running.
However, after the background script gets unloaded at some point in time (non persistent background page, default behavior for a manifest V3 extension), the background script is not reloaded by the message from the native app (background script still appears unloaded in the developer menu of Safari, double-checked using a counter stored in browser.storage.local incremented on message reception). In this case, the completion handler of the application gets no error (error == nil) as if the message was correctly delivered.
I was able to reproduce this behavior with the sample app delivered for WWDC20 (after upgrading the manifest from v2 to v3 to make it non-persistent).
Is it supposed to work ? What I'm doing wrong ?
I'd like to know the install state of my iOS safari extension in the associated swift app. Is there any way to get this? As we have seen it is available for macOS here, is there anyway to know iOS Safari extension is enabled or not?
Thanks
Safari 18.0.1 on macOS 15.01 doesn't support the Passkey PRF extension during cross-device WebAuthn authentication when using QR code scanning, while it works correctly with iCloud passkeys.
Steps to Reproduce:
Clone and setup:
git clone https://github.com/quocle108/passkey-prf-test
yarn
yarn start
Test iCloud Passkey Flow:
Open http://localhost:3000 in Safari
Open DevTools (Cmd+Option+I)
Click "Register"
Choose "Passkey on iCloud"
Expected console output: PRF supported: true
Test Cross-Device Flow:
Click "Register"
Choose "Phone/Tablet"
Scan QR with mobile device
Expected: PRF supported: true
PRF extension should be supported in cross-device flow, matching iCloud passkey behavior.
Actual: PRF supported: false
Cross-device flow returns empty extension results.
Verify in Chrome
Repeat steps 2-3 in Chrome
Both flows return proper PRF extension results: PRF supported: true
Test Environment:
Browser: Safari 18.1.1 , Chrome 131.0.6778.70
OS: macOS 15.01
Mobile: iOS 18.x / Galaxy Note9 Android 10
Test repo: https://github.com/quocle108/passkey-prf-test
Dear Apple Developer Support,
We are currently developing a system that requires the ability to edit Japanese vertical text within the Safari browser on iPhone. During our investigation, we encountered an issue that matches the following WebKit bug:
283620 – Caret Positioning Issues in Vertical Writing Mode
We understand that this issue is being addressed in the following pull request:
https://github.com/WebKit/WebKit/pull/39939
However, it appears that a complete fix has not yet been implemented.
Given this situation, we would like to confirm the following:
Is there any known workaround for this issue in iOS 17.5 or iOS 18.5 (the latest versions as of now)?
If a workaround exists, could you please provide details?
If not, could you share the expected timeline for a full resolution of this issue?
Although this appears to be an open-source WebKit issue, we are reaching out to Apple because WebKit is tightly integrated with iOS and Safari, and ultimately delivered as part of the iPhone experience.
Thank you very much for your support.
Best regards,
Takao Kurabayashi
Topic:
Safari & Web
SubTopic:
General
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 !
We are encountering an issue where the Safari extension we are developing stops working while in use on relatively new iOS versions (confirmed on 17.5.1, 17.6.1, and 18). Upon checking the Safari console, the content script is displayed in the extension script, so the background script or Service Worker must be stopping. The time until it stops is about 1 minute on 17.5.1 and about one day on 17.6.1 or 18.
When it stops, we would like to find a way to restart the Service Worker from the extension side, but we have not found a method to do so yet. To restart the extension, the user needs to turn off the corresponding extension in the iPhone settings and then turn it back on.
As mentioned in the following thread, it is written that the above bug was fixed in 17.6, but we recognize that it has not been fixed. https://forums.developer.apple.com/forums/thread/758346
On 17.5.1, adding the following process to the background script prevents it from stopping for about the same time as on 17.6 and above.
// Will be passed into runtime.onConnect for processes that are listening for the connection event
const INTERNAL_STAYALIVE_PORT = "port.connect";
// Try wake up every 9S
const INTERVAL_WAKE_UP = 9000;
// Alive port
var alivePort = null;
// Call the function at SW(service worker) start
StayAlive();
async function StayAlive() {
var wakeup = setInterval(() => {
if (alivePort == null) {
alivePort = browser.runtime.connect({ name: INTERNAL_STAYALIVE_PORT });
alivePort.onDisconnect.addListener((p) => {
alivePort = null;
});
}
if (alivePort) {
alivePort.postMessage({ content: "ping" });
}
}, INTERVAL_WAKE_UP);
}
Additionally, we considered methods to revive the Service Worker when it stops, which are listed below. None of the methods listed below resolved the issue.
①
Implemented a process to create a connection again if the return value of sendMessage is null. The determination of whether the Service Worker has stopped is made by sending a message from the content script to the background script and checking whether the message return value is null as follows.
sendMessageToBackground.js
let infoFromBackground = await browser.runtime.sendMessage(sendParam);
if (!infoFromBackground) {
// If infoFromBackground is null, Service Worker should have stopped.
browser.runtime.connect({name: 'reconnect'}); // ← reconnection process
// Sending message again
infoFromBackground = await browser.runtime.sendMessage(sendParam);
}
return infoFromBackground.message;
Background script
browser.runtime.onConnect.addListener((port) => {
if (port.name !== 'reconnect') return;
port.onMessage.addListener(async (request, sender, sendResponse) => {
sendResponse({
response: "response form background",
message: "reconnect.",
});
});
②
Verified whether the service worker could be restarted by regenerating Background.js and content.js.
sendMessageToBackground.js
export async function sendMessageToBackground(sendParam) {
let infoFromBackground = await browser.runtime.sendMessage(sendParam);
if (!infoFromBackground) {
executeContentScript(); // ← executeScript
infoFromBackground = await browser.runtime.sendMessage(sendParam);
}
return infoFromBackground.message;
}
async function executeContentScript() {
browser.webNavigation.onDOMContentLoaded.addListener((details) => {
browser.scripting.executeScript({
target: { tabId: details.tabId },
files: ["./content.js"]
});
});
}
However, browser.webNavigation.onDOMContentLoaded.addListener was not executed due to the following error.
@webkit-masked-url://hidden/:2:58295
@webkit-masked-url://hidden/:2:58539
@webkit-masked-url://hidden/:2:58539
③
Verify that ServiceWorker restarts by updating ContentScripts
async function updateContentScripts() {
try {
const scripts = await browser.scripting.getRegisteredContentScripts();
const scriptIds = scripts.map(script => script.id);
await browser.scripting.updateContentScripts(scriptIds);//update content
} catch (e) {
await errorLogger(e.stack);
}
}
However, scripting.getRegisteredContentScripts was not executed due to the same error as in 2.
@webkit-masked-url://hidden/:2:58359
@webkit-masked-url://hidden/:2:58456
@webkit-masked-url://hidden/:2:58456
@webkit-masked-url://hidden/:2:58549
@webkit-masked-url://hidden/:2:58549
These are the methods we have considered. If anyone knows a solution, please let us know.
It seems fetch() does not include credentials (cookie) even when credentials: include is used and Safari extension has host_permissions for that domain when using from a non-default Safari profile.
It includes credentials (cookie) when using from the default profile (which has the default name Personal).
Is there anyone who has this problem?
I try to request in popup.js like this:
const response = await fetch(
url,
{
method: 'GET',
mode: 'cors',
credentials: 'include',
referrerPolicy: 'no-referrer',
}
);
and it does not include the credentials (cookie) from host_permissions.
I already posted https://developer.apple.com/forums/thread/764279, and opened feedback assistant (FB15307169).
But it is still not fixed yet. (macOS 15.4 beta 3)
I hope this is fixed soon.
After App uses Network.framework PrivacyContext Api, dns has been encrypted, that is good.
But when using wkwebview to load web page, wireshark captures normal dns request sent by wkwebview.
Does wkwebview use DoH to resolve domain? if can, how to config params?
If can not, is there anyway to stop wkwebview sending normal dns, such as local proxy.
Our iOS app uses React Native Webview (based on top of WKWebView) to display content. This webview stays in memory throughtout the app's lifecycle. We are observing a high number of webview content process terminations - around 15% of our sessions. (https://developer.apple.com/documentation/webkit/wknavigationdelegate/webviewwebcontentprocessdidterminate(_:))
What could be the reasons for it? Is there a way to know for sure?
Is the 15% of sessions number something that other apps also experience, or should this be lower?
Thanks!
Topic:
Safari & Web
SubTopic:
General
TLDR: I’m searching for a possibility to allow the usage of passkeys and hardware keys for any website in a wkwebview
INFO: The browser is macOS ONLY
Hi, I couldn’t really find documentation or forums posts on how to implement Webauthn for signin or hardware security keys for a second factor. Or rather where those events are triggered to be handled. In Safari you have that popover, that lets you either authenticate through Passwords or with a security key.
When I visit webauthn.io for testing and click either register or authenticate I get
Told not to present authorization sheet: Error Domain=com.apple.AuthenticationServicesCore.AuthorizationError Code=1 "(null)"
ASAuthorizationController credential request failed with error: Error Domain=com.apple.AuthenticationServices.AuthorizationError Code=1004 "(null)"
If I add
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping @MainActor (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
and
func webView(_ webView: WKWebView, authenticationChallenge challenge: URLAuthenticationChallenge, shouldAllowDeprecatedTLS decisionHandler: @escaping @MainActor (Bool) -> Void)
it doesn’t seem to change anything.
I found something about the ASWebAuthenticationSessionWebBrowserSupported entitlement, but by my understanding this is used so a browser can get opened upon some other app calling a ASWebAuthenticationSession.
Has anyone some guidance for me? I feel like webauthn and yubikey support are important security measures for our users.
https://codeberg.org/miakoring/Amethyst/src/branch/main/Amethyst/Shared/ViewComponents/WebKit/WebViewModel.swift
is the code for my webviewmodel.
Delegates are in the Delecate folder https://codeberg.org/miakoring/Amethyst/src/branch/main/Amethyst/Shared/ViewComponents/WebKit
Hello - we have a Mac application that uses a browser extension and the web extension JS APIs to communicate with Safari. As of macOS 15.4 / Safari 18.4 the tab OnAttached and tab onDetached events are no longer received.
After some testing we verified that the events were working properly as of macOS 15.3 / Safari 18.3 but appear to have been broken in macOS 15.4. Note a similar issue was reported previously for Safari 17.6 and was fixed in macOS 15.0 (FB14324177).
We have made a TestFlight version of our app (Tabby) available to simplify debugging via https://testflight.apple.com/join/Va8Zdv9d.
To reproduce the issue:
Install the Tabby TestFlight build on macOS 15.4 or 15.4.1
Open Safari, go to Safari settings and select the Extensions tab
Enable the Tabby extension and grant permissions to all windows all the time
Open a Safari window with at least 3 tabs
Note the open window and tabs displayed in Tabby
In Safari, perform a tab detach by dragging a tab out of the window
Expected behavior
Within Safari the detached tab should now be in it’s own window, and via the onDetached event Tabby should update to show the tab in it’s own window AND removed from the original window.
Observed
Safari fails to send the onDetached event and Tabby will continue to display the detached tab in its original window in addition to the new window.
You can also use the repro steps above to observe the onDetached event being received or not by Tabby in the Safari developer console. The same steps but re-attaching the tab to the original window can be used to observe the onAttached event being received or not.
We’ve attached two screen recordings to the Feedback ID below, one showing the events working on macOS 15.3, and one showing the events failing to be received on macOS 15.4.1. Note it also fails on macOS 15.4.
FEEDBACK ID: FB17367977
myCode is here
// titleScript = "document.querySelector('#\(rawValue) span')?.textContent"
guard let titleResult = try? await webView.evaluateJavaScript(type.titleScript),
let title = titleResult as? String else { return }
this code has error
Thread 1: Swift runtime failure: Unexpectedly found nil while implicitly unwrapping an Optional value
but edit Code like this
It is works Successful
do {
...
let titleResult = try await webView.evaluateJavaScript(type.titleScript)
let title = titleResult as? String
...
} catch {
LogManager.log(level: .error, self, #function, error, "title is Invalid : \(type.titleScript)")
continue
}
I don't know why guard let _ = try? is Fail
On iPhone 16 running iOS 18.0(Xcode 16.2), cookies configured with SameSite=None; Secure fail to apply correctly—iOS forcibly converts the attribute to SameSite=Lax. As a result, cross-site requests from H5 pages within our app cannot carry the required cookies, causing failures.
Can anyone help me on this?
Thanks in advance.
Hi, I'm using a webview in Swift, where I load an html file locally. Basically I have an angular project built and loaded directly into my app bundle. The webview requires the use of the camera. I request permissions via and javascript, the pop-up appears, I accept the permissions and the app works correctly. Only that after a certain number of seconds, the permissions are requested again. It's as if the webview doesn't cache the accepted permissions.
Is this normal behavior?
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.
I have a Safari extension which allows the user to load their own homepage upon opening a new tab. The extension works by retrieving the homepage URL from UserDefaults and then redirecting to it using window.location.replace. In iOS 18, if the homepage is unable to be loaded due to, for example the user having no internet connection, Safari will go into an rapid loading loop, which eventually stops after a while. This is unlike iOS 17, where trying to reproduce the same scenario will end up with a Safari error page, which should be the expected behaviour.
In short, instead of Safari going into an infinite loading loop, it should display a Safari error page like iOS 17 does.
As this issue is only happening on iOS 18, I am almost certain it's an iOS bug and would appreciate if this can be fixed as soon as possible.
I have created a Feedback Assistant report with ID FB15853821, which contains a sysdiagnose file from my iPhone 16 Pro, as well as two videos, one from my iPhone 16 Pro with iOS 18.2 beta 3 and the other video showing a comparison between iOS 18 and 17. Both videos first show the extension functioning correctly with an active internet connection, but when I disable my internet, the iOS 18 Safari goes into an infinite loop.
Here are the steps to reproduce the issue:
Download the Homepage for Safari app from the App Store: https://apps.apple.com/gb/app/homepage-for-safari/id6481118559
Enter any valid homepage URL, such as https://apple.com and tap Save
Go to Settings -> Apps -> Safari -> Extensions -> Homepage and enable the extension
Make sure Open New Tabs is set to “Homepage”
Turn off both WiFi and cellular data and attempt to open a new tab in Safari
Please note that this also happens with iOS 18.2 beta 4.
My iOS app uses a WKWebView with a WKUIDelegate method (webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:) to handle popup windows. This works for most cases, but during OAuth flows on certain sites (e.g., canva.com), the popup WKWebView attempts to send results back to the main WKWebView using JavaScript like window.opener.postMessage(...). However, window.opener is always null in the popup, preventing the message from being posted and blocking login completion.I've researched this and found suggestions that it's by design, as WKWebView instances are isolated for security reasons. Has anyone encountered this and found a reliable workaround (e.g., bridging communication between the main and popup WKWebViews without relying on window.opener)?