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

114 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Speech synthesis from Safari app extension
I'm making a Safari extension for learning languages. I need speech synthesis for any language the user chooses to learn. I initially tried to make this work within JavaScript, but Safari 18 doesn't reliably list voices for all languages on the web SpeechSynthesis API as described here: https://stackoverflow.com/questions/79179072/how-do-you-use-a-japanese-voice-with-speechsynthesis-in-safari-ios-18 As a workaround, I've had to use AVSpeechSynthesizer in SafariWebExtensionHandler (NSExtensionRequestHandling implementation for the extension). This works in the simulator but not on a real device. I've found this note from Apple in a StackOverflow reply: "Safari extensions are very short-lived, hence not fit for audio playback or speech synthesis. Not being able to validate an app extension in Xcode with a manually-added plist entry for background audio is the designed behavior. The general recommendation is to synthesize speech using JavaScript in conjunction with the Web Speech API." Unfortunately, the suggestion to use the Web Speech API is unsuitable as I just explained. Is there a way to set up a background process in the host app that can do speech synthesis? The app extension would need a way to communicate with this process, and start it if it's not running. Is that possible?
0
0
86
3d
Removing Cookie HTTP Header via declarativeNetRequest
I'm porting to Safari a Chrome/Firefox Extension that makes use of declarativeNetRequest.updateDynamicRules to remove some HTTP headers from requests to a specific URL. This works mostly fine, except for some headers for which this is not allowed by WebKit, such as the Priority header (which is however served by Safari). An annoying corner-case I found is that of the Cookie header. When trying to remove it from the request by adding the following rule { id: <rule id>, priority: <rule priority>, action: { type: "modifyHeaders", requestHeaders: [{ "header": "Cookie", "operation": "remove" }] }, condition: { urlFilter: <my url>, resourceTypes: ["main_frame", "sub_frame"] } } nothing error is thrown, yet the Cookie header is still being sent. This rule however works for other headers, such as Referer. Changing "Cookie" for "cookie" does not help. Questions: Is there an alternative way of removing the Cookie header from the HTTP request? Is this just a bug in WebKit? Is there any way of removing "unsupported" headers such as Priority? Any help or references are appreciated. Edited: more specific description of the corner-case.
0
0
221
2w
SFSafariApplication.dispatchMessage on xcode 16
Hello, We have a Safari extension in the app store for about two years. Our extension relies on syncing the data available in a desktop application to the extension. For this we always used SFSafariApplication.dispatchMessage to sync the data without the extension requesting it. And it used to work just fine. Now it appears that dispatchMessage is being marked as unavailable to extensions, so now xcode 16 is failing to build the extension. Also the documentation (Send messages from the app to JavaScript) still indicates that we can use dispatchMessage to initiate communication from the mac os app. Is there a way to achieve this as it is required for our extension to function, and that's how we have built it for chrome and firefox (one codebase).
1
0
198
2w
Safari goes into an infinite loading loop if it cannot load the webpage
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.
0
0
285
Nov ’24
Safari Web Extensions: browser.webNavigation.getAllFrames by tabId return empty string url, when url is in blob protocol
Hello. Environment Safari version 18.1 (22B81). Problem In my Safari Web Extension i need to determine the url of the active tab. I do it this way: const onError = (error) => { console.error(error); }; const getFrameUrl = async (frames) => { console.info(frames) }; const getAllFrames = (frames) => { browser.webNavigation.getAllFrames({ tabId: frames[0].id }).then(getFrameUrl, onError); }; browser.tabs.onUpdated.addListener(() => { browser.tabs.query({ currentWindow: true, active: true }).then(getAllFrames, onError); }); The problem is that if the tab url is a link in the blob protocol, then the result function browser.webNavigation.getAllFrames({ tabId: tabs[0].id }) is as follows: {frameId: 0, parentFrameId: -1, url: "", errorOccurred: false} In Safari version 17 the correct URL value was returned: {frameId: 0, parentFrameId: -1, url: "blob://<some id>", errorOccurred: false} How can I fix the problem? Environment Safari version 18.1 (22B81).
2
1
375
Nov ’24
iOS18 Static Rulesets Stop Working
iOS16 and iOS17 were fine, but on iOS18, our Safari extension that blocks content via static rulesets randomly stops working. Frequently, when a tab is left in the background for a long time (i.e. hours), the content blocker will stop working (until I either kill safari, or reload the extension). I've debugged this and the background.js script reports the ruleset as being loaded, but nevertheless, our rules aren't applied. I really don't think that it's an issue with the way that the rules are defined, since iOS16 and iOS17 worked fine, and on iOS18, the rules DO work. They just stop working after a while. "declarative_net_request": { "rule_resources": [ { "id": "ruleset_1", "enabled": true, "path": "ruleset_1.json" } ] }, Some theories: I have other content blockers on my phone that have LOTS of rules (adguard). Could I be seeing the effects of too many rules? Can I debug this somehow? Do logs get printed somewhere when the max rule limit is reached? Does the use of private and regular tabs mess things up? Please, any input is appreciated, as all of our logs are normal and error-free.
0
0
245
Nov ’24
Import ES Modules in Content Script. Is it possible?
I'm porting a web extension from Chrome to Safari, and I need to execute a method as a content script that is part of an ES module (in particular its default export). In Chrome I use following snippet (via Stack Overflow) const results = await chrome.scripting.executeScript({ args: ["/js/content_script/main.js"], func: async (path) => { const src = chrome.runtime.getURL(path); const { default: asyncMain } = await import(src); return asyncMain(); } }); In Safari this seems to either not work, cause the Web Extension Background Context window to close, or crash the browser. Am I doing something wrong, or is this not possible?
0
0
202
Nov ’24
Safari 18 DNR redirect regex validation issue
Starting Safari 18, Declarative Net Request redirections are no longer working (it used to be working on Safari 17). It seems to be related to the regex validation that is not working as expected. Here is an example of our DNR rule: { priority: 1, action: { type: 'redirect', redirect: { regexSubstitution: `${scheme}//${extensionHost}/index.html\\1#/\\2`, }, }, condition: { // app.dashlane.com, *.app.dashlane.com regexFilter: '^https?://w*\\.?app\\.dashlane\\.com(\\??[^/#]*)[^#]*#?/?(.*)$', resourceTypes: [ 'main_frame' ], }, } Is it a known issue ? Also, it seems to be related to this existing issue: https://forums.developer.apple.com/forums/thread/763505
0
0
226
Nov ’24
Web Extension : browser.cookies.getAll() does not work
After upgrading to Safari version 18, we encountered an issue with my extension’s background script not being able to access cookies. Previously, in Safari versions 17 and below, the extension worked as expected. Now, when the extension tries to retrieve cookies using browser.cookies.getAll(), it returns an empty list. However, if we open the extension’s developer tools, the cookies are visible and accessible. It seems that Safari only provides cookie data after the developer tools have been opened. However, after relaunching Safari and launching the extension without opening the developer tools, browser.cookies.getAll() still returns an empty list. Has anyone else experienced this? STEPS TO REPRODUCE Download this minimal app : https://www.icloud.com/iclouddrive/0bajlhnuQaG6T5NsFKXEB0U9Q#test%5Fcookies Compile test_mv2 extension (in test_cookies.getAll.zip). Launch test_mv2.app and activate extension. Click on the extension's button (browserAction). Open the developer tools. Observe an empty list of cookies. Click on the extension's button (browserAction). Cookies are retrieved as expected.
2
1
269
Nov ’24
Adding a Safari Extension to Capacitor iOS App as an Application Extension
Hello everyone, I’m working on adding a Safari extension as an application extension to an iOS app created using Capacitor (generated from a React app). My goal is to bundle the Safari extension within the Capacitor app, allowing it to serve as a companion app for the extension. However, I’ve run into issues where the extension does not show up in Safari's extension settings when I run the app on a device or simulator. Here's an overview of what I’ve done so far: I initially used Capacitor’s command line tools to generate the iOS app from my React project. This app runs fine on its own. To add the Safari extension, I’m not developing a platform-specific extension from scratch; instead, I used the Xcode command line to convert a Chrome extension to a Safari iOS extension. The converted extension functions correctly if paired with the default Swift app that comes with the conversion. Right now, I effectively have two products: The base Capacitor app (without the extension), which I want as my main app. The standalone Safari extension bundled with the Swift app (from the conversion process). My question is: How can I merge these two products so that the Capacitor app becomes the companion app for the Safari extension, allowing the extension to show up in Safari's settings? Are there specific configurations I should adjust in Xcode or within the manifest files to make this work seamlessly? Any guidance or best practices from others who have integrated Safari extensions into non-Xcode-based projects would be much appreciated! Thank you!
1
0
289
Nov ’24
iOS18 Safari: Page content loses focus after switching to a new tab with chrome.tabs.update
Hi, I have a Safari extension that works well in iOS before 18, which can switch to a different tab with chrome.tabs.update back and forth by keyboard shortcuts. With iOS 18, as Page content loses its focus, it is impossible to trigger content script directly, I have to manually touch screen to put focus back to page content so that keystroke can trigger my content script to talk with background to call chrome.tabs.update to switch back. Please bring focus to page content after switching to a new tab with chrome.tabs.update.
1
0
236
Nov ’24
Discrepancy in Cookie Consent Options Across iOS 18.0 and 18.1 on Certain Websites
I've observed a discrepancy in cookie consent options between iOS 18.0 and 18.1 on some websites, such as www2.hm.com. On iOS 18.0, I see "Accept All Cookies" and "Only Required Cookies" options, whereas on iOS 18.1, the options change to "Accept All Cookies" and "Cookie Settings." I would like to understand if this behavior is related to differences in how websites detect the operating system version (iOS 18.0 vs. 18.1) or browser changes within the iOS update. Has anyone else experienced similar variations in cookie consent banners, and could this be tied to differences in the user agent or website A/B testing for different OS versions? Any insights or technical clarifications would be appreciated!
0
0
272
Oct ’24
Safari Content Blocker - cannot set bundle name in Safari Extensions list
Hello, I can't figure out how to set the name of a Content Blocker in the Safari extensions list. So far, the Content Blocker name in this list is the Contaning application name. I tried to set the bundle name in Info.plist and tried to locate Info.plist, without success... Since I also bundle a Safari ("chrome") extension, I have two extensions in the list, and it would be fine to display a specific name for each to make it clear for the user.
3
0
360
Oct ’24
After building in Xcode, my extension is not showing in Safari.
Hi, I had been working on an extension without any issues, running it from Xcode and debugging locally in Safari. However, without making any code changes, and after uninstalling the extension, it stopped appearing in Safari after building for local debugging. Does anyone know what might be happening or how I can clean up the system? Thanks a lot and best regards.
5
0
465
Oct ’24
Stuck with "In Review" app review status for 3 weeks
Hello, Is it a normal/usual/expected practice that a Mac App Store submission of a Safari extension takes 3 weeks to review? We have submitted an update for our Safari extension on September 20. Few hours after the submission we got an update stating that the submission state changed to "In Review". Since then it was a complete silence. No updates, no visibility of progress, nothing. We tried to ask Apple Developer Support for help several times and every time got a quite generic response stating that it's still in review which is not helpful considering it takes so long. We also tried to expedite the review a couple of days with no reaction so far. So I am at a bit of a loss on how to proceed. The reason we are stressing this out in several channels is this Safari extension update brings compatibility fixes for the recently released Safari 18 and we are getting customer reports that the old version is not working with Safari 18. That was expected but the hope was that review will not take 3 weeks to complete. Any advice from Apple here or anyone else how to proceed?.. Thanks!
4
0
361
Oct ’24
tabs.executeScript ignores frameId option
As of Safari 18, the tabs.executeScript extension API no longer respects the frameId option passed to it, and instead just runs the script in the top frame. Try running an extension with the following contents on a page with an iFrame (chase.com puts its login form in an iFrame for example). content.js console.log("content.js loaded", location.href); // tabs.executeScript test browser.runtime.sendMessage({ type: "tabs.executeScript" }).then(() => { console.log("tabs.executeScript done"); }); // scripting.executeScript test browser.runtime.sendMessage({ type: "scripting.executeScript" }).then(() => { console.log("scripting.executeScript done"); }); background.js browser.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.type === "tabs.executeScript") { browser.tabs .executeScript(sender.tab.id, { code: 'console.log("THIS IS RUN FROM TABS.EXECUTESCRIPT", location.href);', frameId: sender.frameId, }) .then(sendResponse); } else if (request.type === "scripting.executeScript") { browser.scripting .executeScript({ target: { tabId: sender.tab.id, frameIds: [sender.frameId] }, func: () => { console.log("THIS IS RUN FROM SCRIPTING.EXECUTESCRIPT", location.href); }, }) .then(sendResponse); } }); You'll see that tabs.executeScript runs its contents in the TOP frame, no matter what the target is. Notably, scripting.executeScript DOES respect the frameId. Filed with Feedback ID FB15420092
1
0
285
Oct ’24
Building a Safari extension - but Safari doesn't see it
I'm trying to build a (personal) Safari extension, which should add an HTTP header when visiting a few websites. I'm a newbie at XCode. Using XCode, the build runs and the app runs correctly (the standard boilerplate code tells me that the extension is currently off). However, the extension doesn't appear in Safari>Settings>Extensions at all, so I cannot enable the extension. There are two warnings (warnings? or errors? fatal? or not?): NSBundle file:///System/Library/PrivateFrameworks/MetalTools.framework/ principal class is nil because all fallbacks have failed Unable to create bundle at URL ((null)): normalized URL null ...I'm brand new to XCode so I don't really know whether these errors are fatal, and how to fix them if so. These warnings appear when the app runs, not during the build cycle. The plugin appears when issuing this command in Terminal: pluginkit -mAvvv -p com.apple.Safari.web-extension ...part of that response is: podnewsllc.Podnews-Security.Extension(1.0) Path = /Users/jamescridland/Library/(snip)MyApp.appex UUID = EA41(snip)3519 Timestamp = 2024-10-06 03:54:37 +0000 SDK = com.apple.Safari.web-extension Parent Bundle = /Users/jamescridland/Library/(snip)MyApp.app Display Name = MyAppName Extension Short Name = MyAppName Extension Parent Name = MyAppName Platform = macOS ...so it's visible to Safari, but it doesn't appear in Safari>Settings>Extensions. The codesign command says: --prepared:/Users/jamescridland/(snip)__preview.dylib --validated:/Users/jamescridland/(snip)__preview.dylib --prepared:/Users/jamescridland/(snip).debug.dylib --validated:/Users/jamescridland/(snip).debug.dylib /Users/jamescridland/(snip).appex: valid on disk /Users/jamescridland/(snip).appex: satisfies its Designated Requirement ... so I think it's signed correctly. Checking "Allow unsigned extensions" does not appear to change anything. I've tried running a rebuild of LaunchServices, but that hasn't fixed it. /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user My questions are: Is there a log to help me know what is going wrong? Does anyone have any idea why I can't see the extension in Safari? What next? Sorry for the dumb question.
1
0
389
Oct ’24
Safari Web Extensions: tabs.onRemoved unexpectedly thrown on url changed.
I have noticed that tabs.onRemoved works differently in Safari 18 comparing to other browsers and Safari 17. Open a tab e.g. apple.com Take note of the active tab id using this code: browser.tabs.query({currentWindow: true, active: true}, (x) => console.log(x[0].id)) Add a listener on onRemoved: browser.tabs.onRemoved.addListener(console.log) on the active tab, navigate to e.g. https://developer.mozilla.org Take note of the active tab id again (using the same tabs.query). Expect: there should be no console.log of onRemoved. the active tab id stays the same. Actual: there is a console.log of onRemoved. the active tab id is changed. Please help. If this is a bug introduced in Safari 18, it would break a lot of JS Web extensions.
1
0
426
Oct ’24
declarativeNetRequest.getMatchedRules() does not return the blocked URLs of the current website until refreshed
We used declarativeNetRequest.getMatchedRules() to retrieve the blocked URLs. While we do receive a list, we noticed that the URLs captured do not always reflect the ones the content blocker is actively blocking at that moment. However, upon reloading the same page, the correct URLs appear. Screenshots are attached for your reference. First load: After reload:
2
0
400
Oct ’24