How to make the extension's base URI unchanged after restarting Safari

Hello,


I've filled a radar about this issue: FB7597364 but I'm wondering if anyone has a reliable workaround for this issue.


I have made a Safari app extension which allows users to suspend tabs. Unfortunately, because the baseURI changes each time Safari starts the user sees a "Cannot load page" error in the tabs that were suspended in the previous session, see a suspended page is hosted by the extension it self.



Steps to reproduce:

- Extension opens a new tab with the url, eg: safari-extension://AAAAAAA-0000-1111-2222-A0A0A0A0/7075e8a3/suspended.html

- User restarts Safari

- The tab shows "Page cannot be loaded" beacause the baseURI changed, since, as far as I know, it's not possible to make the baseURI unachangeable like on other browsers.



My temporary workaround (which fails sometimes) is to, when the extension first loads in that session, iterate all tabs and look for urls that match the suspended pattern:


override func validateToolbarItem(in window: SFSafariWindow, validationHandler: @escaping ((Bool, String) -> Void)) {
        // This is called when Safari's state changed in some way that would require the extension's toolbar item to be validated again.
        if (!SafariExtensionHandler.safariFirstLoad) { // static var
            SafariExtensionHandler.safariFirstLoad = true;
           
            print("loaded")
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                SFSafariApplication.getActiveWindow { (activeWindow) in
                    activeWindow?.getActiveTab { (activeTab) in
                        SFSafariExtension.getBaseURI { baseURI in
                            guard let baseURI = baseURI else { return };

                            SFSafariApplication.getAllWindows { windows in
                                for window:SFSafariWindow in windows {
                                    window.getAllTabs { tabs in
                                        var i = 1;
                                        for tab:SFSafariTab in tabs {
                                            tab.getActivePage(completionHandler: { page in
                                                page?.getPropertiesWithCompletionHandler( { properties in
                                                    if (properties?.url != nil) {
                                                        let tabUrl: URL = (properties?.url)!;
                                                       
                                                        i = i+1;
                                                        if (tabUrl.scheme == "safari-extension" && tabUrl.path.hasSuffix("suspended.html") && !tabUrl.absoluteString.starts(with: baseURI.absoluteString)) {
                                                            tab.activate {
                                                                tab.navigate(to: URL(string: "\(baseURI.absoluteString)suspended.html?\(tabUrl.query!)")!);
                                                                if (i >= tabs.count) {
                                                                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                                                                        activeTab?.activate(completionHandler: {
                                                                        });
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                });
                                            });
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        validationHandler(true, "");
    }

Unfortunately this does not work 100% of the times as page?.getPropertiesWithCompletionHandler returns nil sometimes.


Any ideas on what else I could do?

Replies

This isn't something that it is possible to work around. Thanks for filing the bug, I will take a look!


Edit: What kind of content is in these safari-extension:// tabs you are trying to load?

Wish I saw your message before, I filled a TSI meanwhile! 😐


It's a simple page showing the original tab's URL, title and screenshot: https://www.dropbox.com/s/x8c7pnfncixlvhw/Screenshot%202020-03-03%20at%2016.00.14.png?dl=0


Not related to this issue, but I guess it's also not possible to set the favicon of a safari-extension:// page, right?

It is currently not possible to set the favicon of a safari-extension:// page. Would you want it to be your extension's icon? Or something more dynamic?


Thanks for filing the report about restoring tabs! I hope to have an update for you soon.

Thank you for your reply.

Ideally, the favicon would be dynamic, ie. as on a normal web page. If no favicon is specified it could default to the extension's icon.

Hi,


Just saw the TP 104 release, thank you!


There is just one issue that could prove fatal for the extension I developed. Not sure if it's intentional, but the query parameters are stripped from the url when it gets restored. For instance, this is the original url:


safari-extension://2CB9D967-22BA-44F3-B604-7261CE7D0D1F/aafefbf/suspended.html?title=Apple&favicon=https://www.apple.com/favicon.ico&url=https://www.apple.com/


and this is the url after closing and launching Safari TP 104:


safari-extension://6DCE5D9E-209A-44F1-8090-3BB36CD27184/86bca88/suspended.html




Thank you for your attention

@bweinstein
The issue persists in TP 105. I'm afraid this change will get merged to the main Safari release, effectively killing my Safari extension.


Is there anything I can add to the plist file to make Safari not strip the query parameters?
Thank you

I wasn't able to reproduce this in my testing. Can you provide feedback with a test case that reproduces the problem?


Thanks!

Thank you for your reply!
Repro steps:

1. Make the extension open a new tab with the baseURI and a parameter, eg.:

safari-extension://2CB967-22BA-44F3-B604-72611F/aafefbf/test.html?title=Apple&color=red


Here's the code I'm using:

SFSafariApplication.getActiveWindow { activeWindow in
            SFSafariExtension.getBaseURI { baseURI in
                guard let baseURI = baseURI else { return }
                var urlComponents = URLComponents(string: baseURI.appendingPathComponent("test.html").absoluteString);
               
                urlComponents?.queryItems = [
                   URLQueryItem(name: "title", value: "Apple"),
                   URLQueryItem(name: "color", value: "red"),
                ];
                activeWindow?.openTab(with: (urlComponents?.url)!, makeActiveIfPossible: true, completionHandler: {_ in });
            }
        }


3. Wait for the page to load

4. Quit Safari

5. Open Safari


Expectation:

- Safari updates the baseURL of that tab and keeps the query parameters, eg:

safari-extension://11111-new-baseURI-44F3-B604-72611F/o213s/test.html?title=Apple&color=red


Actual:

- Safari sets the tab's url with the baseURI only, stripping the query parameters, eg:

safari-extension://11111-new-baseURI-44F3-B604-72611F/o213s/test.html



Thank you

@bweinstein


Just checked TP 107, the issue remains.


Here's a very short video recording showing the issue, notice the location.href output before and after restarting Safari:

https://dropbox.com/s/kgcfyhb5vquielz/Screen%20Recording%202020-05-15%20at%2023.29.43.mov?dl=0