Categorygithub.com/asticode/go-astilectron
modulepackage
0.30.0
Repository: https://github.com/asticode/go-astilectron.git
Documentation: pkg.go.dev

# README

GoReportCard GoDoc Travis Coveralls

Thanks to go-astilectron build cross platform GUI apps with GO and HTML/JS/CSS. It is the official GO bindings of astilectron and is powered by Electron.

Demo

To see a minimal Astilectron app, checkout out the demo.

It uses the bootstrap and the bundler.

If you're looking for a minimalistic example, run go run example/main.go -v.

Real-life examples

Here's a list of awesome projects using go-astilectron (if you're using go-astilectron and want your project to be listed here please submit a PR):

  • go-astivid Video tools written in GO
  • GroupMatcher Program to allocate persons to groups while trying to fulfill all the given wishes as good as possible
  • Stellite GUI Miner An easy to use GUI cryptocurrency miner for Stellite

Bootstrap

For convenience purposes, a bootstrap has been implemented.

The bootstrap allows you to quickly create a one-window application.

There's no obligation to use it, but it's strongly recommended.

If you decide to use it, read thoroughly the documentation as you'll have to structure your project in a specific way.

Bundler

Still for convenience purposes, a bundler has been implemented.

The bundler allows you to bundle your app for every os/arch combinations and get a nice set of files to send your users.

Quick start

WARNING: the code below doesn't handle errors for readibility purposes. However you SHOULD!

Import go-astilectron

To import go-astilectron run:

$ go get -u github.com/asticode/go-astilectron

Start go-astilectron

// Initialize astilectron
var a, _ = astilectron.New(log.New(os.Stderr, "", 0), astilectron.Options{
    AppName: "<your app name>",
    AppIconDefaultPath: "<your .png icon>", // If path is relative, it must be relative to the data directory
    AppIconDarwinPath:  "<your .icns icon>", // Same here
    BaseDirectoryPath: "<where you want the provisioner to install the dependencies>",
    VersionAstilectron: "<version of Astilectron to utilize such as `0.33.0`>",
    VersionElectron: "<version of Electron to utilize such as `4.0.1` | `6.1.2`>",
})
defer a.Close()

// Start astilectron
a.Start()

// Blocking pattern
a.Wait()

For everything to work properly we need to fetch 2 dependencies : astilectron and Electron. .Start() takes care of it by downloading the sources and setting them up properly.

In case you want to embed the sources in the binary to keep a unique binary you can use the NewDisembedderProvisioner function to get the proper Provisioner and attach it to go-astilectron with .SetProvisioner(p Provisioner). Or you can use the bootstrap and the bundler. Check out the demo to see how to use them.

Beware when trying to add your own app icon as you'll need 2 icons : one compatible with MacOSX (.icns) and one compatible with the rest (.png for instance).

If no BaseDirectoryPath is provided, it defaults to the executable's directory path.

The majority of methods are asynchronous which means that when executing them go-astilectron will block until it receives a specific Electron event or until the overall context is cancelled. This is the case of .Start() which will block until it receives the app.event.ready astilectron event or until the overall context is cancelled.

HTML paths

NB! All paths in HTML (and Javascript) must be relative, otherwise the files will not be found. To make this happen in React for example, just set the homepage property of your package.json to "./".

{ "homepage": "./" }

Create a window

// Create a new window
var w, _ = a.NewWindow("http://127.0.0.1:4000", &astilectron.WindowOptions{
    Center: astikit.BoolPtr(true),
    Height: astikit.IntPtr(600),
    Width:  astikit.IntPtr(600),
})
w.Create()

When creating a window you need to indicate a URL as well as options such as position, size, etc.

This is pretty straightforward except the astilectron.Ptr* methods so let me explain: GO doesn't do optional fields when json encoding unless you use pointers whereas Electron does handle optional fields. Therefore I added helper methods to convert int, bool and string into pointers and used pointers in structs sent to Electron.

Open the dev tools

When developing in JS, it's very convenient to debug your code using the browser window's dev tools:

// Open dev tools
w.OpenDevTools()

// Close dev tools
w.CloseDevTools()

Add listeners

// Add a listener on Astilectron
a.On(astilectron.EventNameAppCrash, func(e astilectron.Event) (deleteListener bool) {
    log.Println("App has crashed")
    return
})

// Add a listener on the window
w.On(astilectron.EventNameWindowEventResize, func(e astilectron.Event) (deleteListener bool) {
    log.Println("Window resized")
    return
})

Nothing much to say here either except that you can add listeners to Astilectron as well.

Play with the window

// Play with the window
w.Resize(200, 200)
time.Sleep(time.Second)
w.Maximize()

Check out the Window doc for a list of all exported methods

Send messages from GO to Javascript

Javascript

// This will wait for the astilectron namespace to be ready
document.addEventListener('astilectron-ready', function() {
    // This will listen to messages sent by GO
    astilectron.onMessage(function(message) {
        // Process message
        if (message === "hello") {
            return "world";
        }
    });
})

GO

// This will send a message and execute a callback
// Callbacks are optional
w.SendMessage("hello", func(m *astilectron.EventMessage) {
        // Unmarshal
        var s string
        m.Unmarshal(&s)

        // Process message
        log.Printf("received %s\n", s)
})

This will print received world in the GO output

Send messages from Javascript to GO

GO

// This will listen to messages sent by Javascript
w.OnMessage(func(m *astilectron.EventMessage) interface{} {
        // Unmarshal
        var s string
        m.Unmarshal(&s)

        // Process message
        if s == "hello" {
                return "world"
        }
        return nil
})

Javascript

// This will wait for the astilectron namespace to be ready
document.addEventListener('astilectron-ready', function() {
    // This will send a message to GO
    astilectron.sendMessage("hello", function(message) {
        console.log("received " + message)
    });
})

This will print "received world" in the Javascript output

Play with the window's session

// Clear window's HTTP cache
w.Session.ClearCache()

Handle several screens/displays

// If several displays, move the window to the second display
var displays = a.Displays()
if len(displays) > 1 {
    time.Sleep(time.Second)
    w.MoveInDisplay(displays[1], 50, 50)
}

Menus

// Init a new app menu
// You can do the same thing with a window
var m = a.NewMenu([]*astilectron.MenuItemOptions{
    {
        Label: astikit.StrPtr("Separator"),
        SubMenu: []*astilectron.MenuItemOptions{
            {Label: astikit.StrPtr("Normal 1")},
            {
                Label: astikit.StrPtr("Normal 2"),
                OnClick: func(e astilectron.Event) (deleteListener bool) {
                    log.Println("Normal 2 item has been clicked")
                    return
                },
            },
            {Type: astilectron.MenuItemTypeSeparator},
            {Label: astikit.StrPtr("Normal 3")},
        },
    },
    {
        Label: astikit.StrPtr("Checkbox"),
        SubMenu: []*astilectron.MenuItemOptions{
            {Checked: astikit.BoolPtr(true), Label: astikit.StrPtr("Checkbox 1"), Type: astilectron.MenuItemTypeCheckbox},
            {Label: astikit.StrPtr("Checkbox 2"), Type: astilectron.MenuItemTypeCheckbox},
            {Label: astikit.StrPtr("Checkbox 3"), Type: astilectron.MenuItemTypeCheckbox},
        },
    },
    {
        Label: astikit.StrPtr("Radio"),
        SubMenu: []*astilectron.MenuItemOptions{
            {Checked: astikit.BoolPtr(true), Label: astikit.StrPtr("Radio 1"), Type: astilectron.MenuItemTypeRadio},
            {Label: astikit.StrPtr("Radio 2"), Type: astilectron.MenuItemTypeRadio},
            {Label: astikit.StrPtr("Radio 3"), Type: astilectron.MenuItemTypeRadio},
        },
    },
    {
        Label: astikit.StrPtr("Roles"),
        SubMenu: []*astilectron.MenuItemOptions{
            {Label: astikit.StrPtr("Minimize"), Role: astilectron.MenuItemRoleMinimize},
            {Label: astikit.StrPtr("Close"), Role: astilectron.MenuItemRoleClose},
        },
    },
})

// Retrieve a menu item
// This will retrieve the "Checkbox 1" item
mi, _ := m.Item(1, 0)

// Add listener manually
// An OnClick listener has already been added in the options directly for another menu item
mi.On(astilectron.EventNameMenuItemEventClicked, func(e astilectron.Event) bool {
    log.Printf("Menu item has been clicked. 'Checked' status is now %t\n", *e.MenuItemOptions.Checked)
    return false
})

// Create the menu
m.Create()

// Manipulate a menu item
mi.SetChecked(true)

// Init a new menu item
var ni = m.NewItem(&astilectron.MenuItemOptions{
    Label: astikit.StrPtr("Inserted"),
    SubMenu: []*astilectron.MenuItemOptions{
        {Label: astikit.StrPtr("Inserted 1")},
        {Label: astikit.StrPtr("Inserted 2")},
    },
})

// Insert the menu item at position "1"
m.Insert(1, ni)

// Fetch a sub menu
s, _ := m.SubMenu(0)

// Init a new menu item
ni = s.NewItem(&astilectron.MenuItemOptions{
    Label: astikit.StrPtr("Appended"),
    SubMenu: []*astilectron.MenuItemOptions{
        {Label: astikit.StrPtr("Appended 1")},
        {Label: astikit.StrPtr("Appended 2")},
    },
})

// Append menu item dynamically
s.Append(ni)

// Pop up sub menu as a context menu
s.Popup(&astilectron.MenuPopupOptions{PositionOptions: astilectron.PositionOptions{X: astikit.IntPtr(50), Y: astikit.IntPtr(50)}})

// Close popup
s.ClosePopup()

// Destroy the menu
m.Destroy()

A few things to know:

  • when assigning a role to a menu item, go-astilectron won't be able to capture its click event
  • on MacOS there's no such thing as a window menu, only app menus therefore my advice is to stick to one global app menu instead of creating separate window menus
  • on MacOS MenuItem without SubMenu is not displayed

Tray

// New tray
var t = a.NewTray(&astilectron.TrayOptions{
    Image:   astikit.StrPtr("/path/to/image.png"),
    Tooltip: astikit.StrPtr("Tray's tooltip"),
})

// Create tray
t.Create()

// New tray menu
var m = t.NewMenu([]*astilectron.MenuItemOptions{
    {
        Label: astikit.StrPtr("Root 1"),
        SubMenu: []*astilectron.MenuItemOptions{
            {Label: astikit.StrPtr("Item 1")},
            {Label: astikit.StrPtr("Item 2")},
            {Type: astilectron.MenuItemTypeSeparator},
            {Label: astikit.StrPtr("Item 3")},
        },
    },
    {
        Label: astikit.StrPtr("Root 2"),
        SubMenu: []*astilectron.MenuItemOptions{
            {Label: astikit.StrPtr("Item 1")},
            {Label: astikit.StrPtr("Item 2")},
        },
    },
})

// Create the menu
m.Create()

// Change tray's image
time.Sleep(time.Second)
t.SetImage("/path/to/image-2.png")

Notifications

// Create the notification
var n = a.NewNotification(&astilectron.NotificationOptions{
	Body: "My Body",
	HasReply: astikit.BoolPtr(true), // Only MacOSX
	Icon: "/path/to/icon",
	ReplyPlaceholder: "type your reply here", // Only MacOSX
	Title: "My title",
})

// Add listeners
n.On(astilectron.EventNameNotificationEventClicked, func(e astilectron.Event) (deleteListener bool) {
	log.Println("the notification has been clicked!")
	return
})
// Only for MacOSX
n.On(astilectron.EventNameNotificationEventReplied, func(e astilectron.Event) (deleteListener bool) {
	log.Printf("the user has replied to the notification: %s\n", e.Reply)
	return
})

// Create notification
n.Create()

// Show notification
n.Show()

Dock (MacOSX only)

// Get the dock
var d = a.Dock()

// Hide and show the dock
d.Hide()
d.Show()

// Make the Dock bounce
id, _ := d.Bounce(astilectron.DockBounceTypeCritical)

// Cancel the bounce
d.CancelBounce(id)

// Update badge and icon
d.SetBadge("test")
d.SetIcon("/path/to/icon")

// New dock menu
var m = d.NewMenu([]*astilectron.MenuItemOptions{
    {
        Label: astikit.StrPtr("Root 1"),
        SubMenu: []*astilectron.MenuItemOptions{
            {Label: astikit.StrPtr("Item 1")},
            {Label: astikit.StrPtr("Item 2")},
            {Type: astilectron.MenuItemTypeSeparator},
            {Label: astikit.StrPtr("Item 3")},
        },
    },
        {
        Label: astikit.StrPtr("Root 2"),
        SubMenu: []*astilectron.MenuItemOptions{
            {Label: astikit.StrPtr("Item 1")},
            {Label: astikit.StrPtr("Item 2")},
        },
    },
})

// Create the menu
m.Create()

Dialogs

Add the following line at the top of your javascript file :

const { dialog } = require('electron').remote

Use the available methods.

Basic auth

// Listen to login events
w.OnLogin(func(i astilectron.Event) (username, password string, err error) {
	// Process the request and auth info
	if i.Request.Method == "GET" && i.AuthInfo.Scheme == "http://" {
		username = "username"
		password = "password"
	}
    return
})

Features and roadmap

  • custom branding (custom app name, app icon, etc.)
  • window basic methods (create, show, close, resize, minimize, maximize, ...)
  • window basic events (close, blur, focus, unresponsive, crashed, ...)
  • remote messaging (messages between GO and Javascript)
  • single binary distribution
  • multi screens/displays
  • menu methods and events (create, insert, append, popup, clicked, ...)
  • bootstrap
  • dialogs (open or save file, alerts, ...)
  • tray
  • bundler
  • session
  • accelerators (shortcuts)
  • dock
  • notifications
  • loader
  • file methods (drag & drop, ...)
  • clipboard methods
  • power monitor events (suspend, resume, ...)
  • desktop capturer (audio and video)
  • window advanced options (add missing ones)
  • window advanced methods (add missing ones)
  • window advanced events (add missing ones)
  • child windows

Cheers to

go-thrust which is awesome but unfortunately not maintained anymore. It inspired this project.

# Packages

No description provided by the author

# Functions

AstilectronDownloadSrc returns the download URL of the (currently platform-independent) astilectron zip file.
DefaultExecuter represents the default executer.
Disembed is a cancellable disembed of an src to a dst using a custom Disembedder.
Download is a cancellable function that downloads a src into a dst using a specific *http.Client and cleans up on failed downloads.
ElectronDownloadSrc returns the download URL of the platform-dependant electron zipfile.
IsValidOS validates the OS.
New creates a new Astilectron instance.
NewAccelerator creates a new accelerator.
NewDisembedderProvisioner creates a provisioner that can provision based on embedded data.
Unzip unzips a src into a dst.

# Constants

Versions.
Versions.
Versions.
Dock bounce types.
Dock bounce types.
App event names.
Sends an event to Electron to properly quit the app.
Cancel the context which results in exiting abruptly Electron's app.
App event names.
App event names.
App event names.
App event names.
App event names.
App event names.
Display event names.
Display event names.
Display event names.
Menu event names.
Menu event names.
Menu event names.
Menu event names.
Menu item event names.
Menu item event names.
Menu item event names.
Menu item event names.
Menu item event names.
Menu item event names.
Menu item event names.
Menu item event names.
Menu item event names.
Notification event names.
Notification event names.
Notification event names.
Notification event names.
Notification event names.
Power event names.
Power event names.
Power event names.
Power event names.
Power event names.
Power event names.
Power event names.
Power event names.
Power event names.
Session event names.
Session event names.
Session event names.
Session event names.
Session event names.
Session event names.
Session event names.
Sub menu event names.
Sub menu event names.
Sub menu event names.
Sub menu event names.
Sub menu event names.
Sub menu event names.
Sub menu event names.
Sub menu event names.
Tray event names.
Tray event names.
Tray event names.
Tray event names.
Tray event names.
Tray event names.
Tray event names.
Tray event names.
Tray event names.
Tray event names.
Tray event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Window event names.
Message box types.
Message box types.
Message box types.
Message box types.
Message box types.

# Variables

MacOSX.
All.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item roles.
Menu item types.
Menu item types.
Menu item types.
Menu item types.
Title bar styles.
Title bar styles.
Title bar styles.

# Structs

Astilectron represents an object capable of interacting with Astilectron.
Display represents a display https://github.com/electron/electron/blob/v1.8.1/docs/api/structures/display.md.
DisplayOptions represents display options https://github.com/electron/electron/blob/v1.8.1/docs/api/structures/display.md.
Dock represents a dock https://github.com/electron/electron/blob/v1.8.1/docs/api/app.md#appdockbouncetype-macos.
Event represents an event.
EventAuthInfo represents an event auth info.
EventDisplays represents events displays.
EventMenu represents an event menu.
EventMenuItem represents an event menu item.
EventMessage represents an event message.
EventRequest represents an event request.
EventSecondInstance represents data related to a second instance of the app being started.
EventSubMenu represents a sub menu event.
Menu represents a menu https://github.com/electron/electron/blob/v1.8.1/docs/api/menu.md.
MenuItem represents a menu item.
MenuItemOptions represents menu item options We must use pointers since GO doesn't handle optional fields whereas NodeJS does.
MenuPopupOptions represents menu pop options.
MessageBoxOptions represents message box options We must use pointers since GO doesn't handle optional fields whereas NodeJS does.
Notification represents a notification https://github.com/electron/electron/blob/v1.8.1/docs/api/notification.md.
NotificationOptions represents notification options.
Options represents Astilectron options.
Paths represents the set of paths needed by Astilectron.
Position represents a position.
PositionOptions represents position options.
ProvisionStatus represents the provision status.
ProvisionStatusPackage represents the provision status of a package.
Rectangle represents a rectangle.
RectangleOptions represents rectangle options.
Session represents a session TODO Add missing session methods TODO Add missing session events https://github.com/electron/electron/blob/v1.8.1/docs/api/session.md.
Size represents a size.
SizeOptions represents size options.
SubMenu represents an exported sub menu.
Supported represents Astilectron supported features.
TrafficLightPosition represents traffic light positions (macOS only) https://www.electronjs.org/docs/latest/tutorial/window-customization#create-frameless-windows.
Tray represents a tray.
TrayOptions represents tray options We must use pointers since GO doesn't handle optional fields whereas NodeJS does.
TrayPopUpOptions represents Tray PopUpContextMenu options.
WebPreferences represents web preferences in window options.
Window represents a window TODO Add missing window options TODO Add missing window methods TODO Add missing window events.
WindowAppDetails represents window app details https://github.com/electron/electron/blob/v4.0.1/docs/api/browser-window.md#winsetappdetailsoptions-windows.
WindowCustomOptions represents window custom options.
WindowLoadOptions represents window load options https://github.com/electron/electron/blob/v1.8.1/docs/api/browser-window.md#winloadurlurl-options.
WindowOptions represents window options We must use pointers since GO doesn't handle optional fields whereas NodeJS does.
WindowProxyOptions represents window proxy options https://github.com/electron/electron/blob/v1.8.1/docs/api/session.md#sessetproxyconfig-callback.

# Interfaces

Provisioner represents an object capable of provisioning Astilectron.

# Type aliases

Accelerator represents an accelerator https://github.com/electron/electron/blob/v1.8.1/docs/api/accelerator.md.
CallbackMessage represents a message callback.
Disembedder is a functions that allows to disembed data from a path.
Executer represents an object capable of executing Astilectron run command.
Listener represents a listener executed when an event is dispatched.
ListenerMessage represents a message listener executed when receiving a message from the JS.