Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Úplný funkční příklad najdete v ukázce Flutter v tomto úložišti.
Tato příručka ukazuje, jak pomocí rozhraní příkazového winapp řádku s aplikací Flutter přidat identitu balíčku a zabalit aplikaci jako MSIX.
Identita balíčku je základním konceptem modelu Windows app. Umožňuje vaší aplikaci přistupovat ke konkrétním rozhraním API Windows (jako jsou oznámení, zabezpečení, rozhraní API AI atd.), mají čisté prostředí pro instalaci a odinstalaci a další.
Standardní sestavení Flutter pro Windows nemá identitu balíčku. Tento průvodce ukazuje, jak ho přidat pro ladění a pak ho zabalit pro distribuci.
Předpoklady
Flutter SDK: Nainstalujte flutter podle oficiální příručky.
winapp CLI: Nainstalujte
winappCLI pomocí wingetu (nebo aktualizujte, pokud už je nainstalováno):winget install Microsoft.winappcli --source winget
1. Vytvoření nové aplikace flutter
Podle pokynů v oficiální dokumentaci flutter vytvořte novou aplikaci a spusťte ji.
Měla by se zobrazit výchozí aplikace čítače Flutter.
2. Aktualizace kódu pro kontrolu identity
Aplikaci aktualizujeme a zkontrolujeme, jestli běží s identitou balíčku. K volání rozhraní API Windows GetCurrentPackageFamilyName použijeme metodu Dart FFI.
Nejprve přidejte ffi balíček:
flutter pub add ffi
Dále nahraďte obsah lib/main.dart následujícím kódem. Tento kód se pokusí načíst identitu aktuálního balíčku pomocí rozhraní API Windows. V případě úspěchu se v uživatelském rozhraní zobrazí název rodiny balíčků; v opačném případě se zobrazí "Není zabaleno".
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),
),
);
}
}
Spusťte (program) bez přiřazené identity.
Teď sestavte a spusťte aplikaci obvyklým způsobem:
flutter build windows
Spusťte spustitelný soubor přímo (pokud se liší, nahraďte flutter_app názvem projektu):
.\build\windows\x64\runner\Release\flutter_app.exe
Návod
Výstup sestavení je ve složce x64 bez ohledu na architekturu vašeho počítače – to se očekává pro Windows sestavení Flutter.
Měla by se zobrazit aplikace s oranžovým indikátorem Nenabalené. Tím potvrdíte, že standardní spustitelný soubor běží bez jakékoli identity balíčku.
4. Inicializace Project pomocí rozhraní příkazového řádku winapp
Příkaz winapp init nastaví vše, co potřebujete najednou: manifest aplikace, prostředky a volitelné hlavičky Windows App SDK pro vývoj v C++. Manifest definuje identitu vaší aplikace (název, vydavatel, verzi), která Windows používá k udělení přístupu k rozhraní API.
Spusťte následující příkaz a postupujte podle pokynů:
winapp init
Po zobrazení výzvy:
- Název balíčku: Stisknutím klávesy Enter přijměte výchozí hodnotu (odvozenou z názvu projektu).
- Publisher název: Stisknutím klávesy Enter přijměte výchozí hodnotu nebo zadejte své jméno.
- Verze: Stisknutím klávesy Enter přijměte verzi 1.0.0.0.
- Description: Stisknutím klávesy Enter přijměte výchozí hodnotu (Windows Aplikace).
- Nastavení sad SDK: Pokud chcete stáhnout Windows App SDK a vygenerovat hlavičky C++ (potřebné pro krok 6), vyberte Stabilní sady SDK.
Tento příkaz:
- Vytvoření
Package.appxmanifest– manifest, který definuje identitu vaší aplikace - Vytvoření
Assetssložky – ikony vyžadované pro balení MSIX a odesílání do Storu - Vytvoření složky
.winapps hlavičkami a knihovnami Windows App SDK - Vytvoření konfiguračního
winapp.yamlsouboru pro připnutí verzí sady SDK
Můžete otevřít Package.appxmanifest a upravit vlastnosti, jako je zobrazovaný název, vydavatel a možnosti.
5. Ladění pomocí identity
Pokud chcete otestovat funkce, které vyžadují identitu (jako oznámení), aniž by se aplikace plně zabalily, můžete použít winapp run. Tím se zaregistruje volný balíček rozložení (stejně jako skutečná instalace MSIX) a spustí se aplikace v jednom kroku. Pro ladění není potřeba žádný certifikát ani podepisování.
Sestavení aplikace:
flutter build windowsSpusťte s identitou:
winapp run .\build\windows\x64\runner\Release
Návod
winapp run také zaregistruje balíček ve vašem systému. To je důvod, proč se MSIX může při pokusu o jeho instalaci později v kroku 7 zobrazit jako již nainstalovaný. Slouží winapp unregister k vyčištění vývojových balíčků po dokončení.
Teď by se měla zobrazit aplikace se zeleným indikátorem:
Package Family Name: flutterapp.debug_xxxxxxxx
Tím potvrdíte, že vaše aplikace běží s platnou identitou balíčku.
Návod
Pokročilé ladicí pracovní postupy (připojení ladicích programů, nastavení integrovaného vývojového prostředí, ladění po spuštění) najdete v průvodci laděním.
6. Použití Windows App SDK (volitelné)
Pokud jste během winapp init vybrali nastavit sady SDK, máte nyní přístup k hlavičkám Windows App SDK pro C++ ve složce .winapp/include. Protože Windows runner Flutteru je C++, můžete volat rozhraní API Windows App SDK z nativního kódu a zpřístupnit je Dart prostřednictvím kanálu metod. Pokud potřebujete jenom identitu balíčku pro distribuci, můžete přeskočit ke kroku 7.
Pojďme přidat jednoduchý příklad, který zobrazuje verzi aplikace pro Windows Runtime.
Vytvořte nativní plugin
Vytvořit 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_
Vytvořit 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();
}
Aktualizace CMakeLists.txt
Upravte windows/runner/CMakeLists.txt , abyste udělali tři změny.
add_executable Vyhledejte blok a přidejte "winapp_sdk_plugin.cpp" ho do seznamu zdrojových souborů:
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"
)
Potom na konec souboru přidejte tyto dva řádky, abyste propojili knihovny WinRT a zahrnuli hlavičky Windows App SDK:
# 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")
Registrace modulu plug-in
V windows/runner/flutter_window.cpp, přidejte include do horní části souboru k ostatním include.
#include "winapp_sdk_plugin.h"
Pak najděte RegisterPlugins volání FlutterWindow::OnCreate() a přidejte RegisterWinAppSdkPlugin na řádek hned za ním:
RegisterPlugins(flutter_controller_->engine());
RegisterWinAppSdkPlugin(flutter_controller_->engine()); // <-- add this line
Aktualizace main.dart
Do horní části lib/main.dartpřidejte následující import spolu s existujícími importy:
import 'package:flutter/services.dart';
Přidejte tuto funkci pod existující getPackageFamilyName() funkci (mimo jakoukoli třídu):
/// 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 Do třídy přidejte nové pole vedle existujícího _packageFamilyNamepole:
late final String? _packageFamilyName;
String? _runtimeVersion; // <-- add this line
Aktualizujte initState() tak, aby volalo novou funkci:
@override
void initState() {
super.initState();
_packageFamilyName = getPackageFamilyName();
// Fetch the runtime version asynchronously
getWindowsAppRuntimeVersion().then((version) {
setState(() {
_runtimeVersion = version;
});
});
}
Nakonec v metodě build zobrazte verzi běhového prostředí. Přidejte tento widget do seznamu potomků Column hned za Container widget, který zobrazuje identitu balíčku:
if (_runtimeVersion != null)
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(
'Windows App Runtime: $_runtimeVersion',
style: Theme.of(context).textTheme.bodyLarge,
),
),
Sestavení a spuštění
Znovu sestavte aplikaci:
flutter build windows
winapp run .\build\windows\x64\runner\Release
Teď by se měl zobrazit výstup jako:
Package Family Name: flutterapp.debug_xxxxxxxx
Windows App Runtime: 8000.731.1532.0
Adresář .winapp/include obsahuje všechna potřebná záhlaví pro Windows App SDK, včetně:
-
winrt/– hlavičky projekce WinRT C++ pro přístup k rozhraním API prostředí Windows Runtime -
Microsoft.UI.*.h– hlavičky WinUI 3 pro moderní komponenty uživatelského rozhraní -
MddBootstrap.h– spouštění Windows App SDK -
WindowsAppSDK-VersionInfo.h- Informace o verzi - A mnoho dalších komponent Windows App SDK
Pokud chcete pokročilejší Windows App SDK využití, přečtěte si dokumentaci k Windows App SDK.
7. Balíček s MSIX
Jakmile budete připraveni distribuovat aplikaci, můžete ji zabalit jako MSIX pomocí stejného manifestu.
Příprava adresáře balíčků
Nejprve sestavte aplikaci v režimu vydání:
flutter build windows
Pak vytvořte adresář se soubory vydaných verzí:
mkdir dist
copy .\build\windows\x64\runner\Release\* .\dist\ -Recurse
Výstup sestavení Flutter Windows zahrnuje spustitelný soubor, flutter_windows.dll a složku data – to vše je potřeba.
Vygenerování vývojového certifikátu
Před balením potřebujete vývojový certifikát pro podepisování. Vygenerujte ho, pokud jste to ještě neudělali:
winapp cert generate --if-exists skip
Podepsání a balení
Teď můžete zabalit a podepsat:
winapp pack .\dist --cert .\devcert.pfx
Poznámka: Příkaz
packautomaticky použijePackage.appxmanifestze svého aktuálního adresáře a zkopíruje jej do cílové složky před zabalením.
Instalace certifikátu
Než budete moct nainstalovat balíček MSIX, musíte na svém počítači důvěřovat vývojovému certifikátu. Spusťte tento příkaz jako správce (stačí to udělat jenom jednou pro každý certifikát):
winapp cert install .\devcert.pfx
Instalace a spuštění
Návod
Pokud jste tento balíček použili winapp run v kroku 5, možná už je v systému zaregistrovaný. Nejprve winapp unregister odeberte registraci vývojové verze a pak nainstalujte produkční balíček.
Nainstalujte balíček poklikáním na vygenerovaný .msix soubor nebo pomocí PowerShellu:
Add-AppxPackage .\flutterapp.msix
Návod
Název souboru MSIX zahrnuje verzi a architekturu (např flutterapplication1_1.0.0.0_x64.msix. ). Zkontrolujte přesný název souboru v adresáři. Pokud potřebujete po změně kódu znovu zabalit, navyšte Version v Package.appxmanifest – Windows k aktualizaci nainstalovaného balíčku vyžaduje vyšší číslo verze.
Tips
- Jakmile budete připraveni k distribuci, můžete podepisovat MSIX certifikátem pro podepisování kódu od certifikační autority, aby uživatelé nemuseli instalovat certifikát podepsaný svým držitelem.
- Služba Důvěryhodné podepisování Azure představuje skvělý způsob, jak bezpečně spravovat certifikáty a integrovat přihlašování do kanálu CI/CD.
- Microsoft Store za vás podepíše MSIX, před odesláním se nemusíte podepisovat.
Další kroky
- Distribuujte pomocí winget: Odešlete svůj MSIX do repizitáře Windows Správce balíčků Community
-
Publish do Microsoft Store: Odešlete balíček pomocí
winapp store -
Nastavte CI/CD: Použijte akci
setup-WinAppCliGitHub ke zautomatizování balení v pipeline - prozkoumat rozhraní Windows API: S identitou balíčku teď můžete používat oznámení, AI na zařízení a další rozhraní API závislé na identitě
Windows developer