Ciclo de Vida da Aplicação
Compreendendo o Ciclo de Vida da Aplicação
Seção intitulada “Compreendendo o Ciclo de Vida da Aplicação”Aplicações desktop possuem um ciclo de vida que vai da inicialização até o encerramento. O Wails v3 fornece serviços, eventos e hooks para gerenciar esse ciclo de forma eficaz.
As Etapas do Ciclo de Vida
Seção intitulada “As Etapas do Ciclo de Vida”1. Criação da Aplicação
Seção intitulada “1. Criação da Aplicação”Crie sua aplicação com 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), },})O que acontece:
- As opções são analisadas e validadas
- Os serviços são registrados (mas ainda não iniciados)
- O servidor de assets é configurado
- O runtime é configurado
2. Executando a Aplicação
Seção intitulada “2. Executando a Aplicação”Chame app.Run() para iniciar a aplicação:
err := app.Run() // Blocks until quitif err != nil { log.Fatal(err)}O que acontece:
- Os serviços são iniciados na ordem de registro
- Os ouvintes de eventos são ativados
- As janelas podem ser criadas
- O loop de eventos começa
3. Loop de Eventos
Seção intitulada “3. Loop de Eventos”A aplicação entra no loop de eventos, onde passa a maior parte do seu tempo:
- Eventos do SO são processados (mouse, teclado, eventos de janela)
- Mensagens de Go para JS são tratadas
- Chamadas de JS para Go são executadas
- Atualizações de UI são renderizadas
4. Encerramento
Seção intitulada “4. Encerramento”Quando a aplicação é encerrada:
- O callback
ShouldQuité verificado (se definido) - Os callbacks
OnShutdownsão executados - Os serviços são encerrados na ordem inversa de registro
- As janelas são fechadas
- Os recursos são liberados
Ciclo de Vida dos Serviços
Seção intitulada “Ciclo de Vida dos Serviços”Os serviços são a principal maneira de gerenciar o ciclo de vida no Wails v3. Eles fornecem hooks de inicialização e encerramento através de interfaces. Para documentação completa sobre serviços, consulte o Guia de Serviços.
Criando um Serviço
Seção intitulada “Criando um Serviço”type MyService struct { db *sql.DB}
// ServiceStartup is called when the application startsfunc (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 downfunc (s *MyService) ServiceShutdown() error { if s.db != nil { return s.db.Close() } return nil}Registrando Serviços
Seção intitulada “Registrando Serviços”app := application.New(application.Options{ Services: []application.Service{ application.NewService(&MyService{}), application.NewService(&AnotherService{}), },})Pontos principais:
- Os serviços iniciam na ordem de registro
- Os serviços são encerrados na ordem inversa de registro
- Se o
ServiceStartupde um serviço retornar um erro, a aplicação é abortada - O
ctxpassado paraServiceStartupé cancelado quando o encerramento começa
Usando o Contexto da Aplicação
Seção intitulada “Usando o Contexto da Aplicação”O contexto passado para ServiceStartup é válido durante toda a vida da aplicação:
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}Você também pode acessar o contexto a partir da instância da aplicação:
app := application.Get()ctx := app.Context()Hooks de Nível da Aplicação
Seção intitulada “Hooks de Nível da Aplicação”Estes são callbacks de conveniência em application.Options que permitem integrar-se ao ciclo de vida da aplicação sem criar um serviço completo. Eles são úteis para tarefas simples de limpeza, confirmação de encerramento ou quando você precisa executar código em pontos específicos da sequência de encerramento.
Para gerenciamento de ciclo de vida mais complexo com lógica de inicialização, injeção de dependência ou recursos com estado, use Serviços em vez disso.
ShouldQuit
Seção intitulada “ShouldQuit”O callback ShouldQuit é chamado sempre que um encerramento é solicitado — seja pelo usuário fechando a última janela, pressionando Cmd+Q (macOS) / Alt+F4 (Windows) ou chamando app.Quit() programaticamente.
Valor de retorno:
- Retorne
truepara permitir que o encerramento prossiga (a aplicação será desligada) - Retorne
falsepara cancelar o encerramento (a aplicação continua em execução)
Esta é sua oportunidade de interceptar solicitações de encerramento e opcionalmente impedi-las, por exemplo, para solicitar ao usuário sobre alterações não salvas:
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" },})Se ShouldQuit não estiver definido, a aplicação será encerrada imediatamente quando solicitado.
Quando ShouldQuit é chamado:
- O usuário fecha a última janela (a menos que
DisableQuitOnLastWindowClosedesteja definido) - O usuário pressiona Cmd+Q no macOS
- O usuário pressiona Alt+F4 no Windows (quando focado na última janela)
- O código chama
app.Quit()
Quando ShouldQuit NÃO é chamado:
- O processo é morto (SIGKILL, encerramento forçado pelo Gerenciador de Tarefas)
os.Exit()é chamado diretamente
OnShutdown
Seção intitulada “OnShutdown”O callback OnShutdown é chamado quando a aplicação é confirmada como estando em encerramento (após ShouldQuit retornar true, se definido). Use isso para tarefas de limpeza, como salvar o estado, fechar conexões de banco de dados ou liberar recursos.
app := application.New(application.Options{ OnShutdown: func() { // Save application state saveState()
// Close connections----------|--------------------------------|| macOS | A aplicação continua em execução (a barra de menu permanece) || Windows | A aplicação encerra || Linux | A aplicação encerra |
O macOS segue as convenções nativas da plataforma, onde as aplicações geralmente permanecem ativas na barra de menu mesmo sem janelas abertas. Windows e Linux encerram por padrão.
**Fazer todas as plataformas encerrarem quando a última janela fechar:**
```goapp := application.New(application.Options{ Mac: application.MacOptions{ ApplicationShouldTerminateAfterLastWindowClosed: true, },})Fazer todas as plataformas permanecerem em execução quando a última janela fechar:
Isso é útil para aplicações de bandeja do sistema ou aplicações que devem permanecer em execução em segundo plano.
app := application.New(application.Options{ Windows: application.WindowsOptions{ DisableQuitOnLastWindowClosed: true, }, Linux: application.LinuxOptions{ DisableQuitOnLastWindowClosed: true, },})Padrões Comuns
Seção intitulada “Padrões Comuns”Padrão 1: Serviço de Banco de Dados
Seção intitulada “Padrão 1: Serviço de Banco de Dados”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("falha ao abrir banco de dados: %w", err) }
if err := s.db.PingContext(ctx); err != nil { return fmt.Errorf("falha ao conectar ao banco de dados: %w", err) }
return nil}**Dúvidas sobre o ciclo de vida?** Pergunte no [Discord](https://discord.gg/JDdSxwjhGf) ou verifique os [exemplos](https://github.com/wailsapp/wails/tree/master/v3/examples).