Flutter ile winapp CLI kullanma

Bu kılavuzda winapp CLI'yi flutter uygulamasıyla kullanarak paket kimliği ekleme ve uygulamanızı MSIX olarak paketleme işlemleri gösterilmektedir.

Paket kimliği, Windows app modelinde temel bir kavramdır. Uygulamanızın belirli Windows API'lerine (Bildirimler, Güvenlik, Yapay Zeka API'leri vb.) erişmesini sağlar, sorunsuz yükleme ve kaldırma deneyimi sunar ve daha fazlasını gerçekleştirir.

Önkoşullar

  1. Flutter SDK'sı: Resmi kılavuzu izleyerek Flutter'ı yükleyin.

  2. winapp CLI: CLI'yi winapp winget aracılığıyla yükleyin:

    winget install Microsoft.winappcli --source winget
    

1. Yeni bir Flutter uygulaması oluşturma

Yeni bir uygulama oluşturmak ve uygulamayı çalıştırmak için resmi Flutter belgelerindeki kılavuzu izleyin.

2. Kimliği denetlemek için kodu güncelleştirme

ffi Paketi ekleyin:

flutter pub add ffi

içeriğini lib/main.dart , Dart FFI aracılığıyla Windows GetCurrentPackageFamilyName API'sini kullanarak paket kimliğini denetleen aşağıdaki kodla değiştirin:

import 'dart:ffi';
import 'dart:io' show Platform;

import 'package:ffi/ffi.dart';
import 'package:flutter/material.dart';

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 {
    final result =
        getCurrentPackageFamilyName(length, Pointer<Uint16>.fromAddress(0));
    if (result != 122) return null; // ERROR_INSUFFICIENT_BUFFER = 122

    final namePtr = calloc<Uint16>(length.value);
    try {
      final result2 = getCurrentPackageFamilyName(length, namePtr);
      if (result2 == 0) {
        return namePtr.cast<Utf16>().toDartString();
      }
      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. Kimlik olmadan çalıştırma

Uygulamayı derleme ve çalıştırma:

flutter build windows
.\build\windows\x64\runner\Release\flutter_app.exe

Uygulamayı turuncu "Paketlenmedi" göstergesiyle görmeniz gerekir.

4. winapp CLI ile project başlatma

winapp init

Sorulduğunda:

  • Paket adı: Varsayılanı kabul etmek için Enter tuşuna basın
  • Publisher name: Varsayılanı kabul etmek için Enter tuşuna basın veya adınızı girin
  • Sürüm: 1.0.0.0'ı kabul etmek için Enter'a basın
  • Giriş noktası: Varsayılanı kabul etmek için Enter tuşuna basın (flutter_app.exe)
  • SDK Kurulumu: Windows App SDK'sini indirmek ve C++ başlık dosyalarını oluşturmak için "Sürüm SDK'lar" seçeneğini belirleyin

5. Kimlikle hata ayıklama

  1. Uygulamayı inşa etme

    flutter build windows
    
  2. Hata ayıklama kimliğini uygula:

    winapp create-debug-identity .\build\windows\x64\runner\Release\flutter_app.exe
    
  3. Yürütülebilir dosyayı çalıştırın:

    .\build\windows\x64\runner\Release\flutter_app.exe
    

Paket Aile Adı'nı gösteren yeşil bir göstergeye sahip uygulamayı görmeniz gerekir.

Uyarı

flutter clean çalıştırdıktan veya yeniden derledikten sonra yürütülebilir dosya değiştirildiğinden create-debug-identity yeniden çalıştırmanız gerekir.

6. MSIX ile paketle

  1. Yayın için derleme:

    flutter build windows
    
  2. Paket dizinini hazırlama:

    mkdir dist
    copy .\build\windows\x64\runner\Release\* .\dist\ -Recurse
    
  3. Geliştirme sertifikası oluşturma:

    winapp cert generate --if-exists skip
    
  4. Paketle ve imzala:

    winapp pack .\dist --cert .\devcert.pfx
    
  5. Sertifikayı yükleyin (yönetici olarak çalıştırın):

    winapp cert install .\devcert.pfx
    
  6. Paketi yükleyin:

    Add-AppxPackage .\flutter-app.msix
    

Tavsiye

  • Microsoft Store MSIX'i sizin için imzalar, göndermeden önce imzalamanız gerekmez.
  • Azure Güvenilen İmzalama CI/CD pipelines için sertifikaları güvenli bir şekilde yönetmenin harika bir yoludur.