跳到內容

應用程式生命週期

桌面應用程式具有從啟動到關閉的生命週期。Wails v3 提供了 服務 (Services)事件 (Events)鉤子 (Hooks) 來有效管理此生命週期。

Diagram

使用 application.New() 建立您的應用程式:

app := application.New(application.Options{
Name: "My App",
Description: "An application built with Wails",
Services: []application.Service{
application.NewService(&MyService{}),
},
Assets: application.AssetOptions{
Handler: application.BundledAssetFileServer(assets),
},
})

發生什麼事:

  1. 解析並驗證選項
  2. 註冊服務(但尚未啟動)
  3. 設定資產伺服器
  4. 設定執行階段 (Runtime)

呼叫 app.Run() 以啟動應用程式:

err := app.Run() // Blocks until quit
if err != nil {
log.Fatal(err)
}

發生什麼事:

  1. 依註冊順序啟動服務
  2. 啟用事件監聽器
  3. 可以建立視窗
  4. 開始事件迴圈

應用程式進入事件迴圈,在此期間它花費大部分時間:

  • 處理作業系統事件(滑鼠、鍵盤、視窗事件)
  • 處理 Go 到 JS 的訊息
  • 執行 JS 到 Go 的呼叫
  • 渲染 UI 更新

當應用程式退出時:

  1. 檢查 ShouldQuit 回呼(如果已設定)
  2. 執行 OnShutdown 回呼
  3. 以反向順序關閉服務
  4. 關閉視窗
  5. 釋放資源

服務是 Wails v3 中管理生命週期的主要方式。它們透過介面提供啟動和關閉鉤子。有關服務的完整文件,請參閱 服務指南

type MyService struct {
db *sql.DB
}
// ServiceStartup is called when the application starts
func (s *MyService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
var err error
s.db, err = sql.Open("sqlite3", "app.db")
if err != nil {
return err // Startup aborts if error returned
}
// Run migrations
if err := s.runMigrations(); err != nil {
return err
}
return nil
}
// ServiceShutdown is called when the application shuts down
func (s *MyService) ServiceShutdown() error {
if s.db != nil {
return s.db.Close()
}
return nil
}
app := application.New(application.Options{
Services: []application.Service{
application.NewService(&MyService{}),
application.NewService(&AnotherService{}),
},
})

重點:

  • 服務依註冊順序啟動
  • 服務以反向註冊順序關閉
  • 如果服務的 ServiceStartup 傳回錯誤,應用程式將中止
  • 傳遞給 ServiceStartupctx 在關閉開始時會被取消

傳遞給 ServiceStartup 的上下文在應用程式的整個生命週期內都有效:

func (s *MyService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
// Start a background task that respects shutdown
go func() {
ticker := time.NewTicker(5 * time.Minute)
defer ticker.Stop()
for {
select {
case <-ticker.C:
s.performBackgroundSync()
case <-ctx.Done():
// Application is shutting down
return
}
}
}()
return nil
}

您也可以從應用程式實例存取上下文:

app := application.Get()
ctx := app.Context()

這些是 application.Options 中的便利回呼,讓您可以掛鉤到應用程式生命週期,而無需建立完整服務。它們對於簡單的清理任務、退出確認,或當您需要在關閉序列的特定點執行程式碼時非常有用。

對於具有啟動邏輯、依賴注入或狀態資源的更複雜生命週期管理,請改用 服務

ShouldQuit 回呼會在請求退出時被呼叫——無論是由使用者關閉最後一個視窗、按下 Cmd+Q (macOS) / Alt+F4 (Windows),或以程式設計方式呼叫 app.Quit()

傳回值:

  • 傳回 true 以允許退出繼續進行(應用程式將關閉)
  • 傳回 false 以取消退出(應用程式繼續執行)

這是您攔截退出請求並選擇性地阻止它們的機會,例如提示使用者關於未儲存的變更:

app := application.New(application.Options{
ShouldQuit: func() bool {
if !hasUnsavedChanges() {
return true // No unsaved changes, allow quit
}
// Prompt the user
result, _ := application.QuestionDialog().
SetTitle("Unsaved Changes").
SetMessage("You have unsaved changes. Quit anyway?").
AddButton("Quit", "quit").
AddButton("Cancel", "cancel").
Show()
// Only quit if user clicked "Quit"
return result == "quit"
},
})

如果未設定 ShouldQuit,應用程式將在請求時立即退出。

ShouldQuit 被呼叫時:

  • 使用者關閉最後一個視窗(除非設定了 DisableQuitOnLastWindowClosed
  • 使用者在 macOS 上按下 Cmd+Q
  • 使用者在 Windows 上按下 Alt+F4(當焦點在最後一個視窗上時)
  • 程式碼呼叫 app.Quit()

ShouldQuit 未被呼叫時:

  • 程序被終止 (SIGKILL、工作管理員強制退出)
  • 直接呼叫 os.Exit()

OnShutdown 回呼在應用程式確認要退出時被呼叫(在 ShouldQuit 傳回 true 之後,如果已設定)。用於清理任務,例如儲存狀態、關閉資料庫連線或釋放資源。

app := application.New(application.Options{
OnShutdown: func() {
// Save application state
saveState()
// Close connections------|------|
| macOS | 應用程式繼續執行選單列保持存在|
| Windows | 應用程式退出 |
| Linux | 應用程式退出 |
macOS 遵循原生平台慣例即使沒有視窗應用程式通常仍會活躍於選單列中Windows Linux 預設會退出
**使所有平台在最後一個視窗關閉時退出**
```go
app := application.New(application.Options{
Mac: application.MacOptions{
ApplicationShouldTerminateAfterLastWindowClosed: true,
},
})

使所有平台在最後一個視窗關閉時繼續執行:

這對於系統匣應用程式或應在背景保持執行的應用程式很有用。

app := application.New(application.Options{
Windows: application.WindowsOptions{
DisableQuitOnLastWindowClosed: true,
},
Linux: application.LinuxOptions{
DisableQuitOnLastWindowClosed: true,
},
})
type DatabaseService struct {
db *sql.DB
}
func (s *DatabaseService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
var err error
s.db, err = sql.Open("sqlite3", "app.db")
if err != nil {
return fmt.Errorf("failed to open database: %w", err)
}
if err := s.db.PingContext(ctx); err != nil {
return fmt.Errorf("failed to connect to database: %w", err)
}
return nil
}**對生命週期有疑問** 請在 [Discord](https://discord.gg/JDdSxwjhGf) 提問或查看 [範例](https://github.com/wailsapp/wails/tree/master/v3/examples)。