esc

Good add-ons

An add-on runs on someone's Mac all day, beside the camera, with their trust. These are the habits that keep it welcome: work only while it's seen, keep its things to itself, and say clearly what it does.

Work while it's seen

A list nobody is looking at doesn't need refreshing. Ledge tells your add-on which of its surfaces are on screen, so it can read and fetch while someone looks and stop when they don't:

handlers.onVisibilityChange = { visibility in
    if visibility.isVisible(Surface.notchPage) {
        await notes.reload()          // the page opened: show what's new
    }
    await poller.run(visibility.isAnythingVisible)
}

A surface counts while it's on screen: the notch page while its tab is open, a widget while it's open on the Widgets page, the settings page while it's shown in Settings, and menu bar tiles while the panel is open. Live activities, lock screen pills and player buttons aren't listed, because they're up for as long as you send them. Work the user started, like a timer or a download, carries on unseen; polling for a surface nobody has open doesn't.

Keep your things to yourself

  • Files go in LedgeHost.dataFolder(). It survives updates, and the user decides whether it goes when they remove the add-on.
  • Settings from LedgeHost.set are a plain JSON file on disk. Tokens, passwords and API keys go in the Keychain, under your add-on's id as the service name, with a way for the user to remove them. Better still, use an account Ledge manages, and never hold the token at all.
  • Read other apps through their public interfaces only, never their private files or databases. See Working with other apps.
  • Log that something failed, never what it read: no note text, song history or account names in your logs.

Off until the user turns it on

Anything that costs battery, takes something over or sends something about the user starts off, with a switch on your settings page: a location lookup for the weather, a background scan, a page that holds the notch open. An empty state says how to start, with a “Set up” button that calls LedgeHost.openSettings().

  • Ask before anything destructive, with a confirmed button, and prefer the Trash to deleting.
  • Use .attention only while something really needs acting on. It's what lets you open the notch, and users turn off add-ons that cry wolf.
  • Take activities down the moment they have nothing to say.

Words

  • English first: the manifest, the README and every default string. Other languages are translations on top.
  • Sentence case everywhere: “Show seconds”, not “Show Seconds”, and never all capitals.
  • Whole sentences with the values in them, not sentences glued from pieces, so they can be translated.
  • Short titles. A page's title sits beside the camera, with room for a word or two.
  • One name: the manifest's name, the page title and the settings page say the same thing.

Choose your id once

The id in addon.json names the add-on's folder, its settings and its data on every Mac that installs it, so it can't change after the first release. Name the product: an add-on called Notes is notes, not my-notes-addon.

Credit, and your own marks

  • Name every library, artwork, sound or data set you didn't make in your README, with its licence and a link.
  • Artwork and data need a licence that allows them in a product. “Free to use” on a website isn't one.
  • No other company's logo or icon anywhere in the add-on. When it works with a service, say so in words, like “Sign in with Spotify”, and use your own symbol for what it does.