Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Egy teljes munkapéldáért tekintse meg az adattár Flutter-mintáját .
Ez az útmutató bemutatja, hogyan használhatja a winapp cli-t egy Flutter-alkalmazással a csomagidentitás hozzáadásához és az alkalmazás MSIX-ként való csomagolásához.
A csomagidentitás a Windows app modell alapvető fogalma. Lehetővé teszi, hogy az alkalmazás hozzáférjen bizonyos Windows API-khoz (például értesítések, biztonság, AI API-k stb.), tiszta telepítési/eltávolítási felülettel rendelkezik, és így tovább.
A standard Flutter Windows buildek nem rendelkeznek csomagidentitással. Ez az útmutató bemutatja, hogyan lehet egy elemet hozzáadni hibakereséshez, majd hogyan csomagolhatja be terjesztés céljából.
Előfeltételek
Flutter SDK: Telepítse a Fluttert a hivatalos útmutatót követve.
winapp parancssori felület: Telepítse a parancssori felületet a
winappwingettel (vagy frissítse, ha már telepítve van):winget install Microsoft.winappcli --source winget
1. Új Flutter-alkalmazás létrehozása
Kövesse az útmutatót a hivatalos Flutter-dokumentációban egy új alkalmazás létrehozásához és futtatásához.
Az alapértelmezett Flutter-számláló alkalmazásnak kell megjelennie.
2. Kód frissítése az identitás ellenőrzéséhez
Frissítjük az alkalmazást, hogy ellenőrizze, a csomagazonossággal fut-e. A Dart FFI használatával hívjuk meg a Windows GetCurrentPackageFamilyName API-t.
Először adja hozzá a ffi csomagot:
flutter pub add ffi
Ezután cserélje le a lib/main.dart tartalmát az alábbi kóddal. Ez a kód a Windows API használatával próbálja lekérni az aktuális csomagidentitást. Ha sikeres, megjeleníti a csomagcsalád nevét a felhasználói felületen; ellenkező esetben a "Nincs csomagolva" felirat jelenik meg.
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. Futtatás identitás nélkül
Most hozza létre és futtassa az alkalmazást a szokásos módon:
flutter build windows
Futtassa közvetlenül a végrehajtható fájlt (cserélje le flutter_app a projekted nevét, ha eltér):
.\build\windows\x64\runner\Release\flutter_app.exe
Jótanács
A build kimenete a x64 mappában található, függetlenül a gép architektúrájától – ez a Flutter Windows buildjéhez várható.
Az alkalmazást narancssárga "Nincs csomagolva" jelzővel kell látnia. Ez megerősíti, hogy a standard végrehajtható fájl csomagidentitás nélkül fut.
4. A Project inicializálása winapp parancssori felülettel
A winapp init parancs minden szükséges elemet beállít egy lépésben: alkalmazásjegyzéket, objektumokat és opcionálisan Windows App SDK fejléceket a C++ fejlesztéshez. A jegyzék meghatározza az alkalmazás identitását (név, közzétevő, verzió), amelyet Windows api-hozzáférés biztosításához használ.
Futtassa a következő parancsot, és kövesse az utasításokat:
winapp init
Amikor a rendszer kéri:
- Csomag neve: Nyomja le az Enter billentyűt az alapértelmezett (a projekt nevéből származtatott) elfogadásához
- Publisher név: Az Enter billentyűt lenyomva fogadja el az alapértelmezett értéket, vagy adja meg a nevét
- Verzió: Nyomja le az Enter billentyűt az 1.0.0.0 elfogadásához
- Description: Nyomja le az Enter billentyűt az alapértelmezett (Windows alkalmazás) elfogadásához
- Setup SDK-k: Válassza a "Stabil SDK-k" lehetőséget a Windows App SDK letöltéséhez és C++ fejlécek létrehozásához (a 6. lépéshez szükséges)
Ez a parancs a következő lesz:
- Létrehozza
Package.appxmanifest– az alkalmazás identitását meghatározó jegyzék - Mappa létrehozása
Assets– az MSIX-csomagoláshoz és az Áruház beküldéséhez szükséges ikonok -
.winappmappa létrehozása Windows App SDK fejlécekkel és kódtárakkal -
winapp.yamlKonfigurációs fájl létrehozása SDK-verziók rögzítéséhez
Megnyithatja Package.appxmanifest az olyan tulajdonságok további testreszabásához, mint a megjelenítendő név, a közzétevő és a képességek.
5. Hibakeresés identitással
Az olyan funkciók teszteléséhez, amelyek identitást igényelnek (mint például az értesítések), az alkalmazás teljes csomagolása nélkül használhatja a winapp run eszközt. Ez regisztrál egy laza elrendezési csomagot (csakúgy, mint egy valódi MSIX-telepítés), és egy lépésben elindítja az alkalmazást. A hibakereséshez nincs szükség tanúsítványra vagy aláírásra.
Az alkalmazás létrehozása:
flutter build windowsFuttatás identitással:
winapp run .\build\windows\x64\runner\Release
Jótanács
winapp run a csomagot a rendszeren is regisztrálja. Ezért előfordulhat, hogy az MSIX "már telepítve" állapotban jelenik meg, amikor később megpróbálja telepíteni a 7. lépésben. A fejlesztési csomagok megtisztítására használható winapp unregister , ha elkészült.
Ekkor megjelenik az alkalmazás egy zöld jelzéssel, amely a következőt mutatja:
Package Family Name: flutterapp.debug_xxxxxxxx
Ez megerősíti, hogy az alkalmazás érvényes csomagazonosítóval fut!
Jótanács
A speciális hibakeresési munkafolyamatokat (hibakeresők csatolása, IDE-beállítás, indítási hibakeresés) a hibakeresési útmutatóban találja.
6. A Windows App SDK használata (nem kötelező)
Ha a winapp init során az SDK-k beállítását választotta, most már hozzáférhet Windows App SDK C++ fejlécekhez a .winapp/include mappában. Mivel a Flutter Windows futója C++, meghívhatja Windows App SDK API-kat natív kódból, és egy metóduscsatornán keresztül elérhetővé teheti őket a Dartnak. Ha csak csomagidentitásra van szüksége a terjesztéshez, ugorjon a 7. lépésre.
Vegyünk fel egy egyszerű példát, amely megjeleníti a Windows-alkalmazás Futtatókörnyezet verzióját.
A natív beépülő modul létrehozása
Hozzon létre 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_
Hozzon létre 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();
}
CMakeLists.txt frissítése
Szerkessze a windows/runner/CMakeLists.txt-et három változtatás elvégzéséhez. Keresse meg a add_executable blokkot, és adja hozzá "winapp_sdk_plugin.cpp" a forrásfájllistához:
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"
)
Ezután adja hozzá ezt a két sort a fájl végéhez a WinRT-kódtárak csatolásához és a Windows App SDK fejlécek hozzáadásához:
# 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")
A beépülő modul regisztrálása
Adja hozzá az windows/runner/flutter_window.cpp include-ot a fájl tetején a többi include-dal együtt.
#include "winapp_sdk_plugin.h"
Ezután keresse meg a RegisterPlugins hívást FlutterWindow::OnCreate() és adja hozzá RegisterWinAppSdkPlugin a közvetlenül utána következő sorba.
RegisterPlugins(flutter_controller_->engine());
RegisterWinAppSdkPlugin(flutter_controller_->engine()); // <-- add this line
A main.dart frissítése
Adja hozzá a következő importálást a meglévők mellé a lib/main.dart tetejére:
import 'package:flutter/services.dart';
Adja hozzá ezt a függvényt a meglévő getPackageFamilyName() függvény alá (bármely osztályon kívül):
/// 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;
}
}
Az osztályban _MyHomePageState adjon hozzá egy új mezőt a meglévőhöz _packageFamilyName:
late final String? _packageFamilyName;
String? _runtimeVersion; // <-- add this line
Frissítsen initState() az új függvény meghívásához:
@override
void initState() {
super.initState();
_packageFamilyName = getPackageFamilyName();
// Fetch the runtime version asynchronously
getWindowsAppRuntimeVersion().then((version) {
setState(() {
_runtimeVersion = version;
});
});
}
Végül jelenítse meg a futtatókörnyezet verzióját a build metódusban. Adja hozzá ezt a widgetet a Column gyermeklistában közvetlenül a Container csomag identitását megjelenítő elem után:
if (_runtimeVersion != null)
Padding(
padding: const EdgeInsets.only(bottom: 16),
child: Text(
'Windows App Runtime: $_runtimeVersion',
style: Theme.of(context).textTheme.bodyLarge,
),
),
Építés és futtatás
Az alkalmazás újraépítése:
flutter build windows
winapp run .\build\windows\x64\runner\Release
Most a következő kimenetnek kell megjelennie:
Package Family Name: flutterapp.debug_xxxxxxxx
Windows App Runtime: 8000.731.1532.0
A .winapp/include könyvtár tartalmazza a Windows App SDK összes szükséges fejlécét, beleértve a következőket:
-
winrt/– WinRT C++ kivetítési fejlécek Windows-futtatókörnyezet API-k eléréséhez -
Microsoft.UI.*.h– WinUI 3 fejlécek modern felhasználói felületi összetevőkhöz -
MddBootstrap.h– Windows App SDK rendszerindítás -
WindowsAppSDK-VersionInfo.h– Verzióadatok - És még sok más Windows App SDK összetevő
A fejlettebb Windows App SDK használatért tekintse meg a Windows App SDK dokumentációját.
7. MSIX csomagolás
Miután készen áll az alkalmazás terjesztésére, ugyanazzal a jegyzékfájllal MSIX-ként csomagolhatja be.
A csomagkönyvtár előkészítése
Először hozza létre az alkalmazást kiadási módban:
flutter build windows
Ezután hozzon létre egy könyvtárat a kiadási fájlokkal:
mkdir dist
copy .\build\windows\x64\runner\Release\* .\dist\ -Recurse
A Flutter Windows build kimenete tartalmazza a végrehajtható, a flutter_windows.dll és a data mappát – mindegyikre szükség van.
Fejlesztési tanúsítvány létrehozása
A csomagolás előtt fejlesztési tanúsítványra van szüksége az aláíráshoz. Hozzon létre egyet, ha még nem tette meg:
winapp cert generate --if-exists skip
Aláírás és csomagolás
Most már csomagolhatja és aláírhatja a következőt:
winapp pack .\dist --cert .\devcert.pfx
Megjegyzés: A
packparancs automatikusan azPackage.appxmanifestaktuális könyvtárból származó fájlt használja, és a csomagolás előtt átmásolja a célmappába.
A tanúsítvány telepítése
Az MSIX-csomag telepítése előtt meg kell bíznia a fejlesztési tanúsítványban a számítógépen. Futtassa ezt a parancsot rendszergazdaként (ezt tanúsítványonként csak egyszer kell elvégeznie):
winapp cert install .\devcert.pfx
Telepítés és futtatás
Jótanács
Ha az 5. lépésben használta winapp run , előfordulhat, hogy a csomag már regisztrálva van a rendszeren. Először winapp unregister távolítsa el a fejlesztési regisztrációt, majd telepítse a kiadási csomagot.
Telepítse a csomagot a létrehozott .msix fájlra duplán kattintva vagy a PowerShell használatával:
Add-AppxPackage .\flutterapp.msix
Jótanács
Az MSIX fájlnév tartalmazza a verziót és az architektúrát (pl. flutterapplication1_1.0.0.0_x64.msix). Ellenőrizze a könyvtárban a pontos fájlnevet. Ha a kódmódosítások után újra kell csomagolnia, növelje a Version értékét a Package.appxmanifest-ben – a Windows magasabb verziószámot igényel egy telepített csomag frissítéséhez.
Tips
- Miután készen áll a terjesztésre, aláírhatja az MSIX-et egy hitelesítésszolgáltató kódaláíró tanúsítványával, hogy a felhasználóknak ne kelljen önaláírt tanúsítványt telepíteniük.
- A Megbízható Azure-aláírás szolgáltatással biztonságosan kezelheti tanúsítványait, és integrálhatja a CI/CD-folyamatba való bejelentkezést.
- A Microsoft Store aláírja Önnek az MSIX-et, a beküldés előtt nem kell aláírnia.
Következő lépések
- Distribute via winget: Küldje el MSIX-ét a Windows Csomagkezelő közösségi adattárba
- Tegye közzé a Microsoft Store-ban: Küldje be a csomagot a
winapp storesegítségével -
Set up CI/CD: A
setup-WinAppCliGitHub Művelettel automatizálhatja a csomagolást a folyamatban - Explore Windows API-k: Csomagidentitással mostantól használhatja az Értesítések, a helyi eszközi AI, és egyéb identitásfüggő API-kat
Windows developer