MyGo
Updater

Official plugins

Updater

An update window in the manner of Sparkle, which checks for updates and offers to install them.

The updater plugin gives an app the update window that Mac users know from Sparkle, on every platform: it checks for updates in the background, shows the release notes of a new version and offers to install it, skip it or remind the user later, then downloads it with a progress bar and relaunches the app into it. It is all Go, with no npm package, and works in apps of web pages and of native UI alike. Its window is a web page, or native UI with native.Plugin, for apps that show no web page at all.

It is built on mygo.Updater, so the app must be built with updates: see auto-updates to sign and publish them.

Set up

Use the plugin in Go:

import (
	"github.com/egoist/mygo"
	"github.com/egoist/mygo/plugins/updater"
)

func main() {
	mygo.Use(updater.Plugin)
	// ...
}
  • It checks in the background 10 seconds after launch, then once a day while the app runs, so a version that came out since the app last ran shows when it opens again. When a new version is out, a window shows its release notes and offers Install Update, Remind Me Later and Skip This Version. Background checks do not offer a skipped version again, but offer the next one.
  • Installing downloads the update with a progress bar, then offers to relaunch; otherwise the update runs at the next launch.
  • With the window's "Automatically download and install updates in the future" checked, background checks install updates without asking, and they run at the next launch.

Builds that cannot update themselves, such as development builds and apps installed by a package manager, never check in the background, and the window says why when the user checks.

Checking from the menu

updater.CheckForUpdates() checks as the user asked: the window shows at once, and says when the app is up to date or the check failed. It also shows updates the user skipped. updater.MenuItem() is a "Check for Updates…" item that calls it, which goes after About on macOS:

mygo.App.SetMenu(mygo.NewMenu([]*mygo.MenuItem{
	{Label: "My App", Submenu: []*mygo.MenuItem{
		{Role: mygo.RoleAbout},
		updater.MenuItem(),
		mygo.Separator(),
		{Role: mygo.RoleQuit},
	}},
	{Role: mygo.RoleEditMenu},
	{Role: mygo.RoleWindowMenu},
}))

A button of the app's page can call CheckForUpdates through a bound method, too. While a check is under way, calling it again brings its window to the front.

Options

updater.New takes options instead of the defaults of updater.Plugin:

mygo.Use(updater.New(updater.Options{
	Interval:               12 * time.Hour, // between checks (default a day)
	DisableAutomaticChecks: true,           // until SetAutomaticChecks(true)
	Icon:                   iconPNG,        // default: icon.png among the resources
}))
  • Interval is the time between background checks, a day by default.
  • DisableAutomaticChecks turns background checks off until SetAutomaticChecks(true), for apps that ask the user first or only check from the menu.
  • Icon is the PNG image of the window; by default, icon.png among the app's resources, the icon that mygo build uses, when there is one.
  • Language and Strings choose and change the window's texts (see languages).

Preferences

The user's choices are kept in updater.json in PathUserData. AutomaticChecks and AutomaticDownloads read them and SetAutomaticChecks and SetAutomaticDownloads change them, for a preferences page; LastCheck returns when the app last checked, and AvailableVersion the newer version it found, for a badge or a settings row ("Version 1.4 is available"): empty before a check, after one that failed or found nothing, and for a skipped version. OnChange calls a function on the main thread whenever one of them changed, after a check (AvailableVersion too) or an answer in the update window as well, so the page can show them again:

// UpdatePreferences tells the preferences page what they are now.
var UpdatePreferences = mygo.NewEvent[Prefs]("update-preferences")

updater.OnChange(func() {
	UpdatePreferences.Broadcast(Prefs{
		AutomaticChecks:    updater.AutomaticChecks(),
		AutomaticDownloads: updater.AutomaticDownloads(),
		LastCheck:          updater.LastCheck(),
	})
})

OnInstalled calls a function on the main thread once an update is installed, from the update window or in the background, before the app relaunches into it. On Windows and Linux the app's executable is the new version's by then, so an app can start its helper processes on it early.

Sparkle asks on the second launch whether to check automatically: apps that want to ask set DisableAutomaticChecks and call SetAutomaticChecks with the answer.

Languages

The window speaks the user's language (App.Locale) when the plugin has it: English, Chinese (Simplified and Traditional), Dutch, French, German, Italian, Japanese, Korean, Polish, Portuguese (Brazil), Russian, Spanish, Turkish and Ukrainian, with their decimal marks and units ("1,5 Mo"). Other languages get English. Language picks one, such as the language the app itself shows, and Strings changes texts or adds languages, by language tag; the fields an app leaves empty keep the plugin's texts:

mygo.Use(updater.New(updater.Options{
	Language: settings.Language, // "" follows the system
	Strings: map[string]updater.Strings{
		"en": {Install: "Update Now"},
		"sv": {Title: "Programuppdatering", Install: "Installera uppdatering" /* … */},
	},
}))

A window speaks the language the app shows when its check begins, and keeps it while it is open. After App.SetLocale, or a change of the user's languages while the app follows them, the next window takes the new one, as does an item that MenuItem returns then: an app that rebuilds its menu in App.OnLocaleChanged gets "Check for Updates…" in the new language.

Some texts are formats, such as AvailableMessage, whose arguments are the app's name, the new version and the running one: indexed verbs (%[2]s) let a language order them. mygo.Use fails when a format does not fit its arguments. go doc github.com/egoist/mygo/plugins/updater.Strings lists the texts and the arguments of the formats.

Languages written from right to left, such as Arabic and Hebrew, get a mirrored window, and release notes take the direction of the language they are written in.

Native UI

The window of updater.Plugin is a web page, so it needs WebKitGTK on Linux and the WebView2 Runtime on Windows 10 even in an app whose own windows all show native UI. Package native draws the same window in native UI instead, and needs no webview:

import (
	"github.com/egoist/mygo"
	"github.com/egoist/mygo/plugins/updater"
	"github.com/egoist/mygo/plugins/updater/native"
)

func main() {
	mygo.Use(native.Plugin) // or native.New(updater.Options{...})
	// ...
}

It takes the same options and speaks the same languages, and everything else is package updater's: updater.MenuItem(), updater.CheckForUpdates() and the preferences work as with updater.Plugin. Use one of the two plugins only. The window looks the same; its release notes are the same Markdown, with text to select and links that open in the browser.

Your own update UI

The window is one way to offer updates. For an interface of your own, such as a banner in the app's page, use mygo.Updater instead of the plugin: see your own update UI.