Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Para obter um exemplo de trabalho completo, confira o Flutter Sample neste repositório.
Este guia demonstra como usar a winapp CLI com um aplicativo Flutter para adicionar a identidade do pacote e empacotar seu aplicativo como um MSIX.
A identidade do pacote é um conceito básico no modelo de Windows app. Ele permite que seu aplicativo acesse APIs de Windows específicas (como Notificações, Segurança, APIs de IA etc.), ter uma experiência de instalação/desinstalação limpa e muito mais.
Um build de Windows do Flutter padrão não tem a identidade do pacote. Este guia mostra como adicionar para depuração e, em seguida, empacotar para distribuição.
Pré-requisitos
SDK do Flutter: instale o Flutter seguindo o guia oficial.
CLI do winapp: instalar a
winappCLI por meio do winget (ou atualizar se já estiver instalado):winget install Microsoft.winappcli --source winget
1. Criar um novo aplicativo Flutter
Siga o guia nos documentos oficiais do Flutter para criar um novo aplicativo e executá-lo.
Você deve ver o aplicativo padrão de contador do Flutter.
2. Atualizar código para verificar identidade
Atualizaremos o aplicativo para verificar se ele está em execução com a identidade do pacote. Usaremos o Dart FFI para chamar a API Windows GetCurrentPackageFamilyName.
Primeiro, adicione o ffi pacote:
flutter pub add ffi
Em seguida, substitua o conteúdo de lib/main.dart pelo seguinte código. Esse código tenta recuperar a identidade do pacote atual usando a API Windows. Se for bem-sucedido, ele exibirá o Nome da Família de Pacotes na interface do usuário; caso contrário, ele mostrará "Não empacotado".
import 'dart:ffi';
import 'dart:io' show Platform;
import 'package:ffi/ffi.dart';
import 'package:flutter/material.dart';
/// Returns the Package Family Name if running with package identity, or null.
String? getPackageFamilyName() {
if (!Platform.isWindows) return null;
final kernel32 = DynamicLibrary.open('kernel32.dll');
final getCurrentPackageFamilyName = kernel32.lookupFunction<
Int32 Function(Pointer<Uint32>, Pointer<Uint16>),
int Function(
Pointer<Uint32>, Pointer<Uint16>)>('GetCurrentPackageFamilyName');
final length = calloc<Uint32>();
try {
// First call to get required buffer length
final result =
getCurrentPackageFamilyName(length, Pointer<Uint16>.fromAddress(0));
if (result != 122) return null; // ERROR_INSUFFICIENT_BUFFER = 122
// Second call with buffer to get the name
final namePtr = calloc<Uint16>(length.value);
try {
final result2 = getCurrentPackageFamilyName(length, namePtr);
if (result2 == 0) {
return namePtr.cast<Utf16>().toDartString(); // ERROR_SUCCESS = 0
}
return null;
} finally {
calloc.free(namePtr);
}
} finally {
calloc.free(length);
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
late final String? _packageFamilyName;
@override
void initState() {
super.initState();
_packageFamilyName = getPackageFamilyName();
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.only(bottom: 24),
decoration: BoxDecoration(
color: _packageFamilyName != null
? Colors.green.shade50
: Colors.orange.shade50,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: _packageFamilyName != null
? Colors.green
: Colors.orange,
),
),
child: Text(
_packageFamilyName != null
? 'Package Family Name:\n$_packageFamilyName'
: 'Not packaged',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyLarge,
),
),
const Text('You have pushed the button this many times:'),
Text(
'$_counter',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
3. Executar sem identidade
Agora, crie e execute o aplicativo como de costume:
flutter build windows
Execute o executável diretamente (substitua flutter_app pelo nome do projeto se diferente):
.\build\windows\x64\runner\Release\flutter_app.exe
Dica
A saída de build está na pasta x64 independentemente da arquitetura do computador. Isso é esperado para o build Windows do Flutter.
Você deve ver o aplicativo com um indicador laranja "Não empacotado". Isso confirma que o executável padrão está em execução sem nenhuma identidade de pacote.
4. Inicializar Project com a CLI do winapp
O comando winapp init configura tudo o que você precisa de uma só vez: manifesto do aplicativo, ativos e, opcionalmente, SDK do Aplicativo Windows cabeçalhos para o desenvolvimento do C++. O manifesto define a identidade do aplicativo (nome, editor, versão) que Windows usa para conceder acesso à API.
Execute o seguinte comando e siga os prompts:
winapp init
Quando solicitado:
- Nome do pacote: Pressione Enter para aceitar o padrão (derivado do nome do projeto)
- Nome do publicador: pressione Enter para aceitar o valor padrão ou insira seu nome
- Versão: Pressione Enter para aceitar 1.0.0.0
- Description: Pressione Enter para aceitar o padrão (aplicativo Windows)
- Setup SDKs: selecione "SDKs estáveis" para baixar SDK do Aplicativo Windows e gerar cabeçalhos C++ (necessários para a etapa 6)
Este comando será:
- Criar
Package.appxmanifest— o manifesto que define a identidade do aplicativo - Criar
Assetspasta — ícones necessários para empacotamento MSIX e envio para a Loja - Criar uma pasta
.winappcom SDK do Aplicativo Windows cabeçalhos e bibliotecas - Criar um
winapp.yamlarquivo de configuração para fixar versões do SDK
Você pode abrir Package.appxmanifest para personalizar ainda mais as propriedades, como o nome de exibição, o editor e os recursos.
5. Depurar com Identidade
Para testar recursos que exigem identidade (como Notificações) sem empacotar totalmente o aplicativo, você pode usar winapp run. Isso registra um pacote de layout solto (como uma instalação real de MSIX) e inicia o aplicativo em uma etapa. Nenhum certificado ou assinatura é necessário para depuração.
Compile o aplicativo:
flutter build windowsExecutar com identidade:
winapp run .\build\windows\x64\runner\Release
Dica
winapp run também registra o pacote em seu sistema. É por isso que o MSIX pode aparecer como "já instalado" quando você tentar instalá-lo posteriormente na etapa 7. Use winapp unregister para limpar pacotes de desenvolvimento quando terminar.
Agora você deve ver o aplicativo com um indicador verde mostrando:
Package Family Name: flutterapp.debug_xxxxxxxx
Isso confirma que seu aplicativo está em execução com uma identidade de pacote válida!
Dica
Para obter fluxos de trabalho avançados de depuração (anexando depuradores, configuração de IDE, depuração de inicialização), consulte o Guia de Depuração.
6. Usando SDK do Aplicativo Windows (opcional)
Se você selecionou configurar os SDKs durante winapp init, agora terá acesso aos cabeçalhos C++ do SDK do Aplicativo Windows na pasta .winapp/include. Como o runner do Windows do Flutter é C++, você pode chamar APIs do SDK do Aplicativo Windows a partir do código nativo e expô-las ao Dart por meio de um canal de método. Se você precisar apenas da identidade do pacote para distribuição, poderá pular para a etapa 7.
Vamos adicionar um exemplo simples que exibe a versão aplicativo do Windows Runtime.
Criar o plug-in nativo
Criar windows/runner/winapp_sdk_plugin.h:
#ifndef RUNNER_WINAPP_SDK_PLUGIN_H_
#define RUNNER_WINAPP_SDK_PLUGIN_H_
#include <flutter/flutter_engine.h>
// Registers a method channel for querying Windows App SDK info.
void RegisterWinAppSdkPlugin(flutter::FlutterEngine* engine);
#endif // RUNNER_WINAPP_SDK_PLUGIN_H_
Criar windows/runner/winapp_sdk_plugin.cpp:
#include "winapp_sdk_plugin.h"
#include <flutter/method_channel.h>
#include <flutter/standard_method_codec.h>
#include <winrt/Microsoft.Windows.ApplicationModel.WindowsAppRuntime.h>
#include <string>
void RegisterWinAppSdkPlugin(flutter::FlutterEngine* engine) {
auto channel = std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
engine->messenger(), "com.example/winapp_sdk",
&flutter::StandardMethodCodec::GetInstance());
channel->SetMethodCallHandler(
[](const flutter::MethodCall<flutter::EncodableValue>& call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
if (call.method_name() == "getRuntimeVersion") {
try {
// Flutter already initializes COM in main.cpp, so we skip
// winrt::init_apartment() here — the apartment is already set up.
auto version = winrt::Microsoft::Windows::ApplicationModel::
WindowsAppRuntime::RuntimeInfo::AsString();
std::string versionStr = winrt::to_string(version);
result->Success(flutter::EncodableValue(versionStr));
} catch (const winrt::hresult_error& e) {
result->Error("WINRT_ERROR", winrt::to_string(e.message()));
} catch (...) {
result->Error("UNKNOWN_ERROR",
"Failed to get Windows App Runtime version");
}
} else {
result->NotImplemented();
}
});
// prevent channel destruction by releasing ownership
channel.release();
}
Atualizar CMakeLists.txt
Edite windows/runner/CMakeLists.txt para fazer três alterações. Localize o add_executable bloco e adicione "winapp_sdk_plugin.cpp" à lista de arquivos de origem:
add_executable(${BINARY_NAME} WIN32
"flutter_window.cpp"
"main.cpp"
"utils.cpp"
"win32_window.cpp"
"winapp_sdk_plugin.cpp" # <-- add this line
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
"Runner.rc"
"runner.exe.manifest"
)
Em seguida, adicione estas duas linhas no final do arquivo para vincular bibliotecas WinRT e incluir os cabeçalhos SDK do Aplicativo Windows:
# Link Windows Runtime libraries for WinRT
target_link_libraries(${BINARY_NAME} PRIVATE "WindowsApp.lib")
# Windows App SDK headers from winapp CLI
target_include_directories(${BINARY_NAME} PRIVATE
"${CMAKE_SOURCE_DIR}/../.winapp/include")
Registrar o plug-in
No windows/runner/flutter_window.cpp, adicione o include no topo do arquivo junto com os outros includes.
#include "winapp_sdk_plugin.h"
Em seguida, encontre a chamada RegisterPlugins em FlutterWindow::OnCreate() e adicione RegisterWinAppSdkPlugin na linha logo após ela.
RegisterPlugins(flutter_controller_->engine());
RegisterWinAppSdkPlugin(flutter_controller_->engine()); // <-- add this line
Atualizar main.dart
Adicione a seguinte importação na parte superior de lib/main.dart, juntamente com as importações existentes:
import 'package:flutter/services.dart';
Adicione essa função abaixo da função existente getPackageFamilyName() (fora de qualquer classe):
/// Queries the Windows App Runtime version via a native method channel.
Future<String?> getWindowsAppRuntimeVersion() async {
if (!Platform.isWindows) return null;
try {
const channel = MethodChannel('com.example/winapp_sdk');
final version = await channel.invokeMethod<String>('getRuntimeVersion');
return version;
} catch (_) {
return null;
}
}
_MyHomePageState Na classe, adicione um novo campo ao lado do existente_packageFamilyName:
late final String? _packageFamilyName;
String? _runtimeVersion; // <-- add this line
Atualize initState() para chamar a nova função:
@override
void initState() {
super.initState();
_packageFamilyName = getPackageFamilyName();
// Fetch the runtime version asynchronously
getWindowsAppRuntimeVersion().then((version) {
setState(() {
_runtimeVersion = version;
});
});
}
Por fim, exiba a versão de runtime no build método. Adicione esse widget dentro da Column lista de filhos, logo após o Container que mostra a identidade do pacote:
if (_runtimeVersion != null)
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(
'Windows App Runtime: $_runtimeVersion',
style: Theme.of(context).textTheme.bodyLarge,
),
),
Compilar e executar
Recompile o aplicativo:
flutter build windows
winapp run .\build\windows\x64\runner\Release
Agora você deve ver uma saída como:
Package Family Name: flutterapp.debug_xxxxxxxx
Windows App Runtime: 8000.731.1532.0
O diretório .winapp/include contém todos os cabeçalhos necessários para SDK do Aplicativo Windows, incluindo:
-
winrt/– Cabeçalhos de projeção do WinRT C++ para acessar APIs do Windows Runtime - cabeçalhos
Microsoft.UI.*.h– WinUI 3 para componentes modernos da interface do usuário -
MddBootstrap.h– inicialização SDK do Aplicativo Windows -
WindowsAppSDK-VersionInfo.h- Informações de versão - E muitos outros componentes do Kit de Desenvolvimento de Aplicativos do Windows
Para obter um uso mais avançado de SDK do Aplicativo Windows, confira a documentação SDK do Aplicativo Windows.
7. Empacotar com MSIX
Quando estiver pronto para distribuir seu aplicativo, você poderá empacotá-lo como um MSIX usando o mesmo manifesto.
Preparar o diretório do pacote
Primeiro, crie seu aplicativo no modo de versão:
flutter build windows
Em seguida, crie um diretório com seus arquivos de versão:
mkdir dist
copy .\build\windows\x64\runner\Release\* .\dist\ -Recurse
A saída de build do Flutter Windows inclui o executável, flutter_windows.dll e uma pasta data — todos os quais são necessários.
Gerar um certificado de desenvolvimento
Antes de empacotar, você precisa de um certificado de desenvolvimento para assinatura. Gere um, se ainda não tiver feito isso.
winapp cert generate --if-exists skip
Assinar e empacotar
Agora você pode empacotar e assinar:
winapp pack .\dist --cert .\devcert.pfx
Observação: o comando
packusa automaticamente oPackage.appxmanifestdo seu diretório atual e copia-o para a pasta de destino antes do empacotamento.
Instalar o certificado
Antes de instalar o pacote MSIX, você precisa confiar no certificado de desenvolvimento em seu computador. Execute este comando como administrador (você só precisa fazer isso uma vez por certificado):
winapp cert install .\devcert.pfx
Instalar e executar
Dica
Se você usou winapp run na etapa 5, o pacote pode já estar registrado em seu sistema. Use winapp unregister primeiro para remover o registro de desenvolvimento e, em seguida, instale o pacote de lançamento.
Instale o pacote clicando duas vezes no arquivo gerado .msix ou usando o PowerShell:
Add-AppxPackage .\flutterapp.msix
Dica
O nome do arquivo MSIX inclui a versão e a arquitetura (por exemplo, flutterapplication1_1.0.0.0_x64.msix). Verifique o diretório para obter o nome de arquivo exato. Se você precisar reempacotar após alterações de código, incremente o Version em seu Package.appxmanifest — Windows requer um número de versão mais alto para atualizar um pacote instalado.
Dicas
- Quando estiver pronto para distribuição, você poderá assinar seu MSIX com um certificado de assinatura de código de uma Autoridade de Certificação para que os usuários não precisem instalar um certificado autoassinado.
- O serviço Assinatura Confiável do Azure é uma ótima maneira de gerenciar seus certificados com segurança e integrar a assinatura no pipeline de CI/CD.
- O Microsoft Store assinará o MSIX para você, não é necessário assinar antes do envio.
Próximas etapas
- Distribute via winget: envie seu MSIX para o repositório da comunidade Windows Gerenciador de Pacotes
-
Publicar na Microsoft Store: use
winapp storepara enviar seu pacote -
Set up CI/CD: Use a Ação do
setup-WinAppCliGitHub para automatizar o empacotamento em seu pipeline - Explore Windows APIs: com a identidade do pacote, agora você pode usar Notificações, IA no dispositivo e outras APIs dependentes de identidade
Windows developer