Bug 263170

Summary: REGRESSION (Safari 17.0): browser.tabs.onActivated API doesn't work
Product: WebKit Reporter: Frederik Riedel <frederik.riedel>
Component: WebKit ExtensionsAssignee: Jon Davis <jond>
Status: RESOLVED CONFIGURATION CHANGED    
Severity: Normal CC: annevk, ap, jond, timothy, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: Safari 17   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
demo project
none
Working none

Description Frederik Riedel 2023-10-15 01:40:07 PDT
Hey Safari + WebKit Team!

This is about the macOS Safari Extension of my app one sec (https://one-sec.app/mac/):

The goal of my app is to interrupt any unintentional attempts to navigate to distracting websites (e.g. open mastodon.social while waiting for WebKit to compile 🙃).

When a target website is opened, a breathing exercise is shown instead (after which the user can decide if they really want to open that website).

With Safari 17.0, one minor feature of my extension broke:

I rely on the onFocusChanged API to detect if the user switches to a different window or app on their computer (to avoid having to wait for the intervention to complete) and then come back 10s later when the breathing animation is finished and the website is unlocked.

However, on Safari 17.0, I noticed that this API does not work anymore. 

Have there been any changes to this?
Or is this a known issue?
Any workarounds?

Thanks a lot and have a nice day!

– Frederik
Comment 1 Radar WebKit Bug Importer 2023-10-15 01:40:16 PDT
<rdar://problem/116975467>
Comment 2 Alexey Proskuryakov 2023-10-16 09:04:47 PDT
Not sure why this was filed as evangelism, moving to a regular component.
Comment 3 Alexey Proskuryakov 2023-10-16 09:08:40 PDT
That said, I don't think that we ever supported the focuschanged event. Could you please add some more details, ideally a test case?
Comment 4 Frederik Riedel 2023-10-16 10:10:47 PDT
Created attachment 468233 [details]
demo project
Comment 5 Frederik Riedel 2023-10-16 10:11:37 PDT
Hey Alexey!

Thanks for your quick reply and thanks for taking care to assign this to the correct component.

I have just talked to the developer who is working on the browser extension, and we are using the browser.tabs.onActivated API, not onFocusChanged. Sorry for the confusion.

Please find a minimal example attached, it is basically the Xcode boilerplate code for a Safari extension including these lines in the background.js:

browser.tabs.onActivated.addListener(async (info) => {
    console.log("this is never called :(");
});
Comment 6 Timothy Hatcher 2023-10-18 14:42:11 PDT
I am not able to reproduce this. I am seeing that event get called whenever I switch tabs. (See attached screenshot.)
Comment 7 Timothy Hatcher 2023-10-18 14:42:33 PDT
Created attachment 468265 [details]
Working
Comment 8 Timothy Hatcher 2023-10-18 15:03:34 PDT
The one sec extension does appear to be hitting an exception / promise error responding to the event:

[Error] Unhandled Promise Rejection: TypeError: "" cannot be parsed as a URL.
	r (background.js:1:15494)

Since the code is obfuscated, it is not clear where the empty string in coming from here. The extension was granted all access to all websites, so it should have access to the tab's URL. And it does show the URL in the popup of the extension, so I know that is working.

I would debug where this is happening to see if you are accessing the right info here.

I suspect the fix to URL parsing for compatibility affected this.
Comment 9 Timothy Hatcher 2023-10-18 15:50:45 PDT
Looks like URL("") has always thrown an error, it just has a better error message in Safari 17.

So the likely issue now is some tab object is returning an empty string for the URL, when a full URL was expected. We do return an empty string when permission hasn't been granted to the tab, but in this case I granted it to all websites.
Comment 10 Timothy Hatcher 2023-10-18 18:38:48 PDT
The empty URL was from the start page, which will be an empty string. This should be handled by the extension, so the exception does not break the extension.

Avoiding empty tabs, I was able to use this extension just fine in Safari 17.
Comment 11 Timothy Hatcher 2023-10-18 18:41:53 PDT
Also, if the user has not granted access to the extension for a specific site, it will be an empty string in the tab result too. So you need to account for that in the extension code, so it does not throw an exception and halt further execution.
Comment 12 Frederik Riedel 2023-10-19 03:11:00 PDT
Timothy! Wow! Thanks a lot for your great help + debugging our obfuscated code!

What you found was the exact reason why this stopped working.

We fixed it now, and the expected result has been restored.

Have a nice day :)

– Frederik 

(PS: not sure what the correct status for this "bug" is now, please feel free to update it accordingly)
Comment 13 Timothy Hatcher 2023-10-19 09:22:09 PDT
Awesome, happy to help!