I'm in the process of building my first Safari extension--a very simple one--but I've run into a couple of problems. The extension boils down to a single, injected script that attempts to bypass the native feed handler and redirect to an http:// URI. My issues so far are twofold:
beforeload
event handler, but can't access my settings using the safari.extension.settings
path indicated in the documentation.I haven't found anything in Apple's documentation to indicate that settings shouldn't be available from my script. Since extensions are such a new feature, even Google returns limited relevant results and most of those are from the official documentation.
What am I missing?
UPDATE
So I'm hoping that the documentation is incomplete because it's borderline abysmal, but I've learned a bit about settings. It turns out that, from injection scripts, the SafariExtensionSettings
object isn't available. Injection scripts only have access to the SafariContentExtension
object (which isn't useful at all), but it's aliased in exactly the same manner (safari.extension.settings
)--bad idea, IMO. As stated in the injection script documentation:
Important: When you use safari.extension from within an injected script, you are not addressing the SafariExtension class. You are addressing the SafariContentExtension class.
You have to use the messaging system to talk to a global HTML file which has access to the settings. It's kind of loopy, but I have a message being sent to a global.html
file that retrieves the settings and will send a message back to my injection script as soon as I figure out how to go about doing that.
Since I'm doing all of my work before the document loads, all of the methods I've found to send message back rely on a page object that I don't have.
In the Safari app , you can install extensions to customize the way your browser works. For example, extensions can help you find coupons when shopping, block content on websites, give you access to features from other apps, and more.
Safari extensions are like little apps that only work inside the web browser on your iPhone. Extensions can help you unlock new features that aren't natively available in Safari. For example, you can use extensions to block content, get rid of ads, enhance security, autofill passwords, and so on.
To debug your extension's pop-up in macOS, click the button for your extension in the Safari toolbar to display the pop-up. Control-click the pop-up and select Inspect Element to display the Web Inspector for the pop-up.
Manage your extensions In the Safari app on your Mac, choose Safari > Settings, then click Extensions. Do any of the following: Turn an extension on or off: Select or deselect the extension's checkbox. Note: You get a warning if you turn on an extension that slows down browsing.
Like everyone else at this point, I'm still climbing the learning curve, but here's how I've handled this problem:
I have a simple extension with no chrome and one injected end script (script.js). For the purpose of loading settings I've added a simple global page (proxy.html). When script.js is injected, it sends a getSettings
message to proxy.html. proxy.html responds with a setSettings
message, and script.js continues initialization.
The most helpful page I've found in the docs on this topic is Messages and Proxies.
proxy.html:
<!doctype html>
<html lang="en">
<head>
<script type="text/javascript">
safari.application.addEventListener( "message", function( e ) {
if( e.name === "getSettings" ) {
e.target.page.dispatchMessage( "setSettings", {
sort_keys: safari.extension.settings.getItem( "sort_keys" )
} );
}
}, false );
</script>
</head>
<body></body>
</html>
script.js:
( function() {
var settings, init = function() {
// do extension stuff
};
// listen for an incoming setSettings message
safari.self.addEventListener( "message", function( e ) {
if( e.name === "setSettings" ) {
settings = e.message;
init();
}
}, false );
// ask proxy.html for settings
safari.self.tab.dispatchMessage( "getSettings" );
}() )
EDIT: like you said in your initial post update, the injected script doesn't have the same kind of access that a global HTML page would have. This is my working solution, imagine you want to know the value of setting "foo" in the injected script:
Injected script code:
function getMessage(msgEvent) {
if (msgEvent.name == "settingValueIs")
alert("Value for asked setting is: " + msgEvent.message);
}
safari.self.tab.dispatchMessage("getSettingValue", "foo"); // ask for value
safari.self.addEventListener("message", getMessage, false); // wait for reply
Global HTML code:
function respondToMessage(messageEvent) {
if (messageEvent.name == "getSettingValue") {
// getItem("foo");
var value = safari.extension.settings.getItem(messageEvent.message);
// return value of foo to injected script
safari.application.activeBrowserWindow.activeTab.page.dispatchMessage("settingValueIs", value);
}
}
safari.application.addEventListener("message",respondToMessage,false);
Hope this helps !
Initial post: I'm having the same 2nd problem as you, I can't access my settings (or secureSettings) from an injected script. In my case the script is loaded after page load, but even that way I can't use safari.extension.settings
.
The only way it works is with a toolbar/button, the HTML behind that element can getItem
and setItem
as expected.
My conclusion is that, for some reason, injected scripts can't access settings (actually, they don't even seem to have access to the safari
element). Bug or intended feature, that's left to figure out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With