Safari Extensions

RSS for tag

Enhance and customize the web browsing experience on Mac, iPhone, and iPad with Safari Extensions

Posts under Safari Extensions tag

136 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Declarative Net Request rules are getting added to the redirect calls
I am creating a Safari Web Extension. There are two calls let say, call1 and call2 which gets executed in sequence by browser, call1 gives a 302 type response and redirects to call2. When creating DNR rule for adding "Cookie" in the request header of call1, the same cookie gets added to the request header of call2 as well(Same is the case for other headers/custom headers as-well). Because of this the set-cookie present in response header of call1 is not sent in the request header of call2, and returns 400 response. The same setting is working fine for other browsers chrome & firefox. Is this a bug or DNR works differently for safari ? currently "webRequestBlocking" works in safari for manifest v3, is there any development of it getting removed just like it's removed in chrome in mv3.
0
0
8
9h
Safari Web Extensions & NSXPCConnection
I have a basic setup following WWDC 2020 on Safari Web Extensions and another one on XPC. The video even mentions that one can use UserDefaults or XPC to communicate with the host app. Here is my setup. macOS 15.2, Xcode 16.2 A macOS app (all targets sandboxed, with an app group) with 3 targets: SwiftUI Hello World web extension XPC Service The web extension itself works and can update UserDefaults, which can then be read by SwiftUI app - everything works by the book. The app can communicate to the XPC service via NSXPCConnection - again, everything works fine. The problem is that the web extension does not communicate with XPC, and this is what I need so that I can avoid using UserDefaults for larger and more complex payloads. Web Ext handler code: class SafariWebExtensionHandler: NSObject, NSExtensionRequestHandling { func beginRequest(with context: NSExtensionContext) { // Unpack the message from Safari Web Extension. let item = context.inputItems[0] as? NSExtensionItem let message = item?.userInfo?[SFExtensionMessageKey] // Update the value in UserDefaults. let defaults = UserDefaults(suiteName: "com.***.AppName.group") let messageDictionary = message as? [String: String] if messageDictionary?["message"] == "Word highlighted" { var currentValue = defaults?.integer(forKey: "WordHighlightedCount") ?? 0 currentValue += 1 defaults?.set(currentValue, forKey: "WordHighlightedCount") } let response = NSExtensionItem() response.userInfo = [ SFExtensionMessageKey: [ "Response to": message ] ] os_log(.default, "setting up XPC connection") let xpcConnection = NSXPCConnection(serviceName: "com.***.AppName.AppName-XPC-Service") xpcConnection.remoteObjectInterface = NSXPCInterface(with: AppName_XPC_ServiceProtocol.self) xpcConnection.resume() let service = xpcConnection.remoteObjectProxyWithErrorHandler { error in os_log(.default, "Received error: %{public}@", error as CVarArg) } as? AppName_XPC_ServiceProtocol service?.performCalculation(firstNumber: 23, secondNumber: 19) { result in NSLog("Result of calculation XPC is: \(result)") os_log(.default, "Result of calculation XPC is: \(result)") context.completeRequest(returningItems: [response], completionHandler: nil) } } } The error I'm getting: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.***.AppName.AppName-XPC-Service was invalidated: failed at lookup with error 3 - No such process." What am I missing?
4
0
53
23h
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
40
1d
Safari Web Extension - ES6 Module Imports Not Working After Enabling "type": "module"
I'm trying to use ES6 module imports in a Safari Web Extension, but despite enabling "type": "module" in the manifest, imports are not functioning as expected. Specifically when working with a project structure that includes multiple directories. A root directory containing the manifest.json and main entry point scripts A scripts/ folder housing core functionality modules A common/ directory for shared utilities, constants, and helper functions A background.js file in the root that attempts to import from these various directories When trying to import modules from the scripts/ and common/ directories into my background.js, I'm encountering complete import failures. How can I correctly implement cross-directory module imports in Safari Web Extensions?
1
0
34
1d
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
0
0
271
1w
Safari extension without native code
I have a simple Safari extension which contains only Javascript and no native code. Currently I have the placeholder SafariWebExtensionHandler.swift that Xcode created when I added the extension. It's not doing anything useful, but simply deleting it doesn't seem to work. Can I have an extension that includes no native code?
2
0
240
2w
fetch() in safari extension does not include credentials (cookie) when using from non-default profile
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.
0
1
238
2w
Safari Web Extension - storage.session not available on iPad v16.3
I'm creating a Safari Web Extension, which successfully uses storage.local and storage.session on MacOS (14.x/15.x) and iOS (15.x,18.x). However, when testing on an iPad running iPadOS 16.3, it fails with an undefined error: TypeError: undefined is not an object (evaluating 'api.storage.session.get') Dropping to the console, I can access 'api.storage.local', but no luck for 'api.storage.session'. First question, why would storage.session not be available? Is there something different on this iPadOS version to enable it? I could just use local storage, but don't need the data to persist. I'll probably just fall back to this solution. Second question, should I instead be using localStorage and sessionStorage? I can't find any helpful direction on if using localStorage vs storage.local is best practice?
1
0
272
2w
Redirecting to an app's universal link from and app extension popup
I have a simple Safari extension for iOS. In its popup, I want a button that will open the app via a universal link. I have this kind-of working, except that Safari opens the actual online destination of the link with a banner at the top saying "Open in the XXXX app" and an OPEN button. What do I have to do to go directly to the app? More generally, I know that if I copy-and-paste a universal link into the Safari address bar, Safari does the same thing - but it does go directly to the app from an <a href="...."> link. In my app extension JavaScript, I set window.location. Presumably this is too similar to pasting into the address bar. Is there some alternative to setting window.location that is more like clicking on a link and will go directly to the universal link's app? Thanks.
5
0
1k
2w
Add background.js to Safari App Extension
I develop a tab manager extension: https://apps.apple.com/ua/app/tab-finder-for-safari/id6741719894 It's written purely in Swift. All Safari interactions are done solely inside a SFSafariExtensionHandler . But now i'm considering adding some features from Google Chrome's Extension API like window switching. Is it possible to add a background.js worker to my existing Safari App Extension to have access to the beginRequest method override inside SFSafariExtensionHandler? Without converting my extension from Safari App Extension to Safari Web Extenion?
1
0
184
2w
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
255
3w
DNR Redirect Rule Won’t Redirect to Extension Path
DNR rules redirecting to an extension path lead to an error page: “Safari can’t open the page. The error is: “The operation couldn’t be completed. (NSURLErrorDomain error -1008.)” (NSURLErrorDomain:-1,008).” Here is a demo extension that replicates the bug: https://github.com/lenacohen/Safari-Test-Extensions/tree/main/dnr-extension-path-redirect This is an example of a redirect rule that leads to an error page instead of the extension path page: chrome.declarativeNetRequest.updateDynamicRules({addRules: [ { id: 2, priority: 1, action: { type: "redirect", redirect: { extensionPath: "/web_accessible_resources/test_redirect.html" } }, condition: { urlFilter: "||washingtonpost.com^", resourceTypes: [ "main_frame" ] } } ]}); The extension path is included in web_accessible_resources in the extension manifest: "web_accessible_resources": [{ "resources": [ "web_accessible_resources/test_redirect.html" ], I also submitted a bug report on Apple's Feedback Assistant: FB16607632
0
0
370
Feb ’25
Safari extension service worker appears with a delay in the Develop dropdown
Hi, I'm developing an extension and I need to debug console logs that are logged in the Service Worker. The worker is configured in the manifest and is generally working as expected: However, when I open the browser, go to any site, and open Develop -> Service Workers or Develop -> Web Extension Background Content it is not visible there, so I can't really access the logs: But then I noticed that if I go out of focus from the browser for some time (and probably let the SW die), it becomes visible and I can open it without an issue: So, a couple of questions: Why isn't it instantly accessible? The extension Service Worker dev tools should be accessible regardless of what is happening to the tab or the browser, even if the SW terminates. Why does it eventually appear under Web Extension Background Content instead of the Service Workers when it is in fact an SW?
0
0
356
Feb ’25
How to trigger Safari App Extension with a keyboard shortcut without a content script and Accessibility permissions?
I have a Safari App Extension which allows users to switch between last open tabs with a shortcut option+tab in the same way it's possible to switch between last open apps with command+tab. Here is how i do it: I inject a content script on all websites which has the only thing – key listener for option+tab presses. When a user presses option+tab, that keyboard listener detects it and sends a message to the Safari Handler. Then Safari Handler sends a message to the containing app and it shows a panel with last open tabs. This approach has a problem: it shows a message to a user in settings: "Can read sensitive info from web pages, including passwords..." Which is bad, because in reality i don't read passwords. If i remove SFSafariContentScript key in the Safari App Extension target's Info.plist, then this message about reading sensitive data disappears, but then i loose the ability to open the tabs panel. How can I open my app window with a shortcut without frightening a user? It's possible to listen to global key presses, but that would require a user to grant the app permissions of Accessibility (Privacy & Security) in macOS system settings, which also sounds shady. I know an app which does not require an Accessibility permission: https://apps.apple.com/ua/app/tabback-lite/id6469582909 and at the same time it does not tell a user about reading sensitive data in the extension settings. Here is my app: https://apps.apple.com/ua/app/tab-finder/id6741719894 It's open-source: https://github.com/kopyl/safari-tab-switcher
2
0
479
Feb ’25
"excludeMatches" array in scripting.registerContentScripts() API is totally ignored in Safari web extensions
In a project to create a web extension for Safari, using scripting.registerContentScript() API to inject a bunch of scripts into web pages, I needed to manage a dynamic whitelist (i.e., web pages where the scripts should not be injected). Fortunately, scripting.registerContentScripts() gives you the option of defining a list of web pages to be considered as a whitelist, using the excludeMatches parameter in the directive, to represent an array of pages where the script should not be injected. Here just a sample of what I mean: const matches = ['*://*/*']; const excludeMatches = ['*://*.example.com/*']; const directive = { id: 'injected-jstest', js: ['injectedscript.js'], matches: matches, excludeMatches: excludeMatches, persistAcrossSessions: false, runAt: 'document_start' }; await browser.scripting.registerContentScripts([directive]) .catch(reason => { console.log("[SW] >>> inject script error:",reason); }); Of course, the whitelist (the excludeMatches array) is not static, but varies over time according to the needs of the moment. Everything works perfectly in Chromium browsers (Chrome, Edge, ...) and Firefox, but fails miserably in Safari. In fact, Safari seems to completely ignore the excludeMatches parameter and injects the script even where it should not. Has anyone had the same problem and solved it somehow? NOTE : To test the correctness and capabilities of the API in each browser, I created a simple repository on Github with the extension code for Chromium, Firefox and Safari (XCode project).
1
0
443
Feb ’25
Safari web extension service worker not working after a minute
We are testing our safari web extension (https://apps.apple.com/us/app/whatfix-for-jnj-centris/id6723895659) on an iPad 7th Gen (iPadOS v - 17.4.1) I am sharing a video link where you can see the widget (named Self Help) appears on the application. However after a couple of refreshes, it vanishes. This widget is powered by the extension. We tried connecting the iPad to Mac and opened the webinspector. The extension content script sends a message to the service worker and it is expected to send back a response which it is not doing We believe it is related to an issue that has been highlighted multiple times in the developer forum - https://developer.apple.com/forums/thread/758346 We have tried using several workaorunds as suggested by peer developers in the thread but we are unable to revive the service worker once it is killed. We would like to understand from you, how to recover from this issue. Is there any workaround that we can apply to make sure that extension works fine? It would be immensely helpful if we can get on a call to explain the issue further Video Link: https://www.icloud.com/iclouddrive/0a7NR7BzDQHHU8zCHERuySBMw#RPReplay%5FFinal1740034010
1
0
272
Feb ’25
Unable to validate with app sandbox issues
My app is a Safari extension. When trying to validate the app, I get the following error: App sandbox not enabled. The following executables must include the "com.apple.security.app-sandbox" entitlement with a Boolean value of true in the entitlements property list: [( "app.rango.Rango.pkg/Payload/Rango for Safari.app/Contents/MacOS/Rango for Safari" )] Refer to App Sandbox page at https://developer.apple.com/documentation/security/app_sandbox for more information on sandboxing your app. I don't know why this is happening. I have app sandbox enabled in both the app and the extension target. I have both entitlement files. When executing codesign -d --entitlements :- /path/to/binary I get the following: <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>com.apple.security.app-sandbox</key><true/><key>com.apple.security.files.user-selected.read-only</key><true/><key>com.apple.security.get-task-allow</key><true/><key>com.apple.security.network.client</key><true/></dict></plist> If I check on Activity Monitor, on the sandbox column it shows true. I have no idea why I keep getting this error when all indicates that the app is actually sandboxed.
4
0
418
Feb ’25