Lewati ke konten

Aplikasi Wails dengan Self-Update

Dalam tutorial ini Anda akan menambahkan updater dalam aplikasi ke aplikasi Wails v3 baru. Di akhir, aplikasi akan:

  • Mengecek GitHub Releases sesuai permintaan (dan opsional dengan timer).
  • Mengunduh asset yang tepat untuk OS + arsitektur yang sedang berjalan.
  • Memverifikasi digest SHA-256 (dan opsional tanda tangan Ed25519) terhadap byte yang diunduh.
  • Menampilkan release notes di jendela update default framework.
  • Menukar biner yang sedang berjalan dan meluncurkan ulang — semua tanpa mengirim executable helper terpisah.

Kita akan menggunakan GitHub Releases sebagai sumber update karena gratis dan tidak memerlukan infrastruktur. Pola yang sama bekerja dengan keygen.sh dan Sparkle AppCast — lihat panduan Updater setelah selesai.


  1. Buat proyek baru dengan template vanilla:

    Terminal window
    wails3 init --template vanilla --name updater-tutorial
    cd updater-tutorial

    Anda sekarang seharusnya memiliki direktori dengan main.go, frontend/, dan Taskfile.yml. Konfirmasi dapat di-build dan diluncurkan:

    Terminal window
    wails3 task dev

    Jendela Wails kosong seharusnya terbuka. Keluar dan lanjutkan.

  2. Buka main.go dan tambahkan dua paket updater ke import Anda:

    main.go
    package main
    import (
    _ "embed"
    "github.com/wailsapp/wails/v3/pkg/application"
    "github.com/wailsapp/wails/v3/pkg/updater"
    "github.com/wailsapp/wails/v3/pkg/updater/providers/github"
    )

    Ini menarik Updater itu sendiri dan provider GitHub Releases.

  3. app.Updater sudah terhubung ke setiap *application.App — Anda hanya perlu memanggil Init:

    main.go
    const currentVersion = "1.0.0"
    gh, err := github.New(github.Config{
    Repository: "yourorg/your-repo", // ← change this
    ChecksumAsset: "SHA256SUMS", // sibling file with sha256 digests
    })
    if err != nil {
    log.Fatalf("github.New: %v", err)
    }
    if err := app.Updater.Init(updater.Config{
    CurrentVersion: currentVersion,
    Providers: []updater.Provider{gh},
    }); err != nil {
    log.Fatalf("Updater.Init: %v", err)
    }

    Tempatkan ini setelah application.New dan sebelum app.Run().

  4. Di main.go yang sama, tambahkan entri menu “Check for Updates…”:

    main.go
    menu := app.Menu.New()
    app.Menu.SetApplicationMenu(menu)
    appMenu := menu.AddSubmenu("App")
    appMenu.Add("Check for Updates…").OnClick(func(*application.Context) {
    go func() {
    if err := app.Updater.CheckAndInstall(context.Background()); err != nil {
    app.Logger.Error("update", "error", err)
    }
    }()
    })

    CheckAndInstall membuka jendela update framework, menjalankan Check, dan jika rilis ditemukan, menjalankan DownloadAndInstall otomatis. Jendela tetap terbuka dalam state “Up to Date” saat tidak ada yang baru — pengguna menutupnya dengan tombol Close.

  5. Terminal window
    wails3 task dev

    Klik App → Check for Updates…. Anda seharusnya melihat jendela update terbuka sebentar, mengakses API GitHub, tidak menemukan rilis lebih baru dari 1.0.0, dan menetap pada state Up to Date dengan ✓ hijau.

    Jika Anda mendapat error di sini, biasanya salah satu dari:

    GejalaPerbaikan
    404 Not FoundField Repository salah — harus owner/repo
    403 rate-limitedTambahkan Token: "ghp_…" ke github.Config (gunakan PAT dengan scope public_repo)
    Network errorsKonfirmasi aplikasi yang berjalan dapat mengakses api.github.com
  6. Naikkan currentVersion di main.go ke 1.0.0 (atau biarkan). Build untuk satu platform untuk mendapatkan biner yang dapat dilampirkan ke rilis:

    Terminal window
    wails3 task build:darwin
    # produces bin/updater-tutorial.app
    # zip it for the release asset:
    cd bin && zip -r updater-tutorial-darwin-arm64.zip updater-tutorial.app && cd ..

    Buat file SHA256SUMS di samping biner:

    Terminal window
    cd bin
    shasum -a 256 updater-tutorial-* > SHA256SUMS
    cat SHA256SUMS

    Anda seharusnya melihat satu atau lebih baris seperti:

    abc123… updater-tutorial-darwin-arm64.zip

    Sekarang terbitkan ini sebagai v2.0.0 di repositori GitHub Anda:

    Terminal window
    gh release create v2.0.0 \
    --title "v2.0.0" \
    --notes "First update for the self-update tutorial.
    - **Bold** Markdown renders in the update window
    - \`Code spans\` too
    - Lists work
    - GFM tables work" \
    bin/SHA256SUMS bin/updater-tutorial-*
  7. Dengan currentVersion masih 1.0.0, jalankan aplikasi lagi:

    Terminal window
    wails3 task dev

    Klik App → Check for Updates…. Kali ini Anda seharusnya melihat sesuatu seperti:

    Jendela updater default dalam state Update Ready, menampilkan pill versi, release notes yang dirender Markdown, dan tombol utama Restart & Apply.
    • Ikon hero berubah dari biru ↓ (“Update Available”) ke hijau ✓ (“Update Ready”).
    • Subtitle menampilkan v1.0.0 → v2.0.0 · <size>.
    • Panel release notes merender Markdown Anda dengan bold, code span, dan tabel.
    • Progress bar terisi selama unduhan (cepat — biner kecil).

    Updater men-stage biner baru di direktori temp. Untuk menyelesaikan update:

    • Klik Restart & Apply.
    • Aplikasi Anda keluar, helper menukar biner, biner baru diluncurkan ulang.
    • Aplikasi yang diluncurkan ulang melaporkan currentVersion = "1.0.0" (karena kita hardcode), tetapi byte di disk sesuai build v2.0.0.

    Di aplikasi nyata, currentVersion akan diset saat build via -ldflags agar biner baru tahu sekarang v2.0.0 dan pengecekan berikutnya tidak menemukan update.

  8. Ganti konstanta dengan variabel build-time:

    main.go
    var (
    currentVersion = "dev" // overridden by -ldflags at release time
    )

    Lalu di perintah build Anda:

    Terminal window
    wails3 task build:darwin -- -ldflags "-X main.currentVersion=2.0.0"

    Atau tambahkan -ldflags ke Taskfile.yml agar mengambil dari git describe --tags.

  9. Tambahkan penandatanganan kriptografis (disarankan untuk produksi)

    Section titled “Tambahkan penandatanganan kriptografis (disarankan untuk produksi)”

    Path SHA256SUMS memverifikasi integritas (byte sesuai yang disimpan GitHub) tetapi bukan autentisitas (byte tersebut diproduksi pipeline rilis Anda, bukan akun maintainer yang dikompromikan). Untuk ketahanan terhadap perubahan, tandatangani setiap rilis dengan kunci Ed25519:

    Terminal window
    # One-time: generate the keypair
    ssh-keygen -t ed25519 -f updater-key -N "" -C "wails-updater"
    # updater-key — keep secret (build server, HSM, password manager)
    # updater-key.pub — bundle in your app

    Untuk setiap rilis, tandatangani digest SHA-256 setiap asset dengan kunci privat Anda. Helper Go kecil:

    cmd/sign-release/main.go
    package main
    import (
    "crypto/ed25519"
    "crypto/sha256"
    "encoding/base64"
    "fmt"
    "io"
    "os"
    )
    func main() {
    priv, _ := os.ReadFile("updater-key")
    key := ed25519.PrivateKey(priv) // raw 64-byte private key
    f, _ := os.Open(os.Args[1])
    defer f.Close()
    h := sha256.New()
    _, _ = io.Copy(h, f)
    sig := ed25519.Sign(key, h.Sum(nil))
    fmt.Println(base64.StdEncoding.EncodeToString(sig))
    }

    Provider GitHub default saat ini tidak mengambil file tanda tangan terpisah — Anda dapat menulis provider kustom yang melakukannya, atau beralih ke keygen.sh yang menandatangani setiap artifact di sisi server dan mengekspos digest dan tanda tangan via API-nya.

    Embed kunci publik di aplikasi Anda:

    main.go
    //go:embed updater-key.pub
    var updaterPublicKey []byte
    app.Updater.Init(updater.Config{
    CurrentVersion: currentVersion,
    PublicKey: updaterPublicKey,
    Providers: []updater.Provider{gh},
    })

    Dengan PublicKey diset, rilis apa pun yang mengirim Signature harus diverifikasi terhadap kunci ini. Sumber rilis tidak dapat mengganti kuncinya sendiri — itulah tujuan pinning out-of-band saat build time.

  10. Jendela default mencakup kasus umum. Tiga jalan keluar jika Anda butuh kontrol lebih — pilih satu berdasarkan seberapa banyak yang ingin disesuaikan:

    app.Updater.Init(updater.Config{
    // …
    Window: &updater.BuiltinWindow{
    CSS: `:root { --accent: #ff6f00; --radius: 16px; }`,
    },
    })

    Lihat bagian Tema via variabel CSS untuk daftar variabel lengkap.

  11. Jalankan pengecekan otomatis di latar belakang

    Section titled “Jalankan pengecekan otomatis di latar belakang”

    Untuk mengecek dengan timer alih-alih (atau selain) klik menu:

    app.Updater.Init(updater.Config{
    CurrentVersion: currentVersion,
    Providers: []updater.Provider{gh},
    PublicKey: updaterPublicKey,
    CheckInterval: 6 * time.Hour,
    })

    Setiap tick menjalankan alur CheckAndInstall yang sama seperti klik manual. Set Window: updater.WindowNone jika Anda ingin pengecekan berkala diam sampai sesuatu benar-benar ditemukan — lalu subscribe ke EventUpdateAvailable sendiri untuk memutuskan UX apa yang ditampilkan.

Anda sekarang memiliki aplikasi Wails yang:

  • Mengecek GitHub Releases untuk update sesuai permintaan dan dengan timer.
  • Merender release notes sebagai Markdown di jendela default yang rapi.
  • Memverifikasi unduhan terhadap digest SHA-256 yang Anda terbitkan.
  • Opsional memverifikasi tanda tangan Ed25519 terhadap kunci publik yang Anda embed saat build time.
  • Menukar biner yang sedang berjalan in-place dan meluncurkan ulang otomatis.
  • Panduan Updater memiliki referensi API lengkap, setiap event, setiap opsi konfigurasi, dan mekanisme swap mode helper.
  • Lihat v3/examples/updater untuk contoh lengkap yang dapat Anda clone.
  • Repo target uji wailsapp/updater-demo menunjukkan tata letak release-asset yang disarankan.
  • Code signing di macOS — Gatekeeper memerlukan biner yang ditukar ditandatangani dan dinotarisasi. Tandatangani bundle .app Anda sebelum zip untuk rilis. Updater mempertahankan byte verbatim; tidak menandatangani ulang apa pun.
  • Antivirus di Windows — file .exe unsigned yang diunduh dari internet dapat memicu peringatan SmartScreen. Tandatangani biner dengan sertifikat Authenticode, atau terima bahwa pengguna di mesin terkunci mungkin perlu whitelist aplikasi Anda.
  • Rilis atomik — terbitkan SHA256SUMS (dan biner Anda) bersama, bukan di commit terpisah. Updater mengambil sidecar terpisah dari biner; jika keduanya drift, pemeriksaan digest gagal closed.
  • Versi yang dilewati — tombol “Skip This Version” jendela default mencatat skip secara lokal. Jika Anda mengirim update keamanan kritis, beri nomor versi baru agar tidak otomatis dilewati pengguna yang menolak rilis sebelumnya.