.NET에서 winapp CLI 사용

이 가이드는 대부분의 .NET 프로젝트 형식에 대해 작동해야 합니다. 이 단계는 WPF 같은 콘솔 및 UI 기반 프로젝트 모두에서 테스트되었습니다. 작업 예제를 보려면 샘플 폴더에서 dotnet-app(콘솔) 및 wpf-app(WPF) 샘플을 확인하세요.

이 가이드에서는 .NET 애플리케이션에서 winapp CLI를 사용하여 패키지 ID로 디버그하고 애플리케이션을 MSIX로 패키지하는 방법을 보여 줍니다.

패키지 ID는 Windows app 모델의 핵심 개념입니다. 이를 통해 애플리케이션은 알림, 보안, AI API 등과 같은 특정 Windows API에 액세스하고, 깨끗한 설치/제거 환경 등을 사용할 수 있습니다.

표준 실행 파일(예: 생성된 dotnet build실행 파일)에는 패키지 ID가 없습니다. 이 가이드에서는 디버깅을 위해 추가한 다음 배포용으로 패키지하는 방법을 보여줍니다.

필수 조건

  1. .NET SDK: .NET SDK를 설치합니다(설치 후 다시 시작해야 합니다.)

    winget install Microsoft.DotNet.SDK.10 --source winget
    
  2. winapp CLI: winget을 winapp 통해 도구를 설치합니다(또는 이미 설치된 경우 업데이트).

    winget install Microsoft.winappcli --source winget
    

1. 새 .NET 앱 만들기

먼저 간단한 .NET 콘솔 애플리케이션을 만듭니다.

dotnet new console -n dotnet-app
cd dotnet-app

실행하여 모든 것이 작동하는지 확인합니다.

dotnet run

출력은 "Hello, World!"여야 합니다.

2. ID를 확인하도록 코드 업데이트

패키지 ID를 사용하여 실행되는지 확인하도록 앱을 업데이트합니다. Windows 런타임 API를 사용하여 패키지 API에 액세스합니다.

먼저 특정 Windows SDK 버전을 대상으로 project 파일을 업데이트합니다. dotnet-app.csproj 열고 Windows SDK 버전을 포함하도록 TargetFramework 변경합니다.

  <TargetFramework>net10.0-windows10.0.26100.0</TargetFramework>

이렇게 하면 추가 패키지 없이도 Windows 런타임 API에 액세스할 수 있습니다.

이제 내용을 다음 코드로 바꿉니다 Program.cs . 이 코드는 Windows 런타임 API를 사용하여 현재 패키지 ID를 검색하려고 시도합니다. 성공하면 패키지 패밀리 이름이 인쇄됩니다. 그렇지 않으면 "패키지되지 않음"을 출력합니다.

using Windows.ApplicationModel;

try
{
    var package = Package.Current;
    var familyName = package.Id.FamilyName;
    Console.WriteLine($"Package Family Name: {familyName}");
}
catch (InvalidOperationException)
{
    // Thrown when app doesn't have package identity
    Console.WriteLine("Not packaged");
}

3. ID 없이 실행

이제 평소와 같이 앱을 실행합니다.

dotnet run

"패키지되지 않음" 출력이 표시됩니다. 그러면 패키지 ID 없이 표준 실행 파일이 실행 중임을 확인합니다.

4. winapp CLI를 사용하여 Project 초기화

winapp init 명령은 자동으로 .csproj 파일을 검색하고 .NET 특정 설정을 실행합니다. 한 번으로 필요한 모든 항목을 설정합니다. 유효성을 검사하고 TargetFramework, 필요한 NuGet 패키지를 추가하고, 앱 매니페스트 및 자산을 생성합니다.

다음 명령을 실행하고 프롬프트를 따릅니다.

winapp init

프롬프트가 표시되면

  • 패키지 이름: Enter 키를 눌러 기본값(dotnet-app)을 적용합니다.
  • Publisher 이름: Enter 키를 눌러 기본값을 적용하거나 이름을 입력합니다.
  • 버전: Enter 키를 눌러 1.0.0.0 허용
  • 설명: Enter 키를 눌러 기본값(Windows 애플리케이션)을 적용하거나 설명을 입력합니다.
  • Windows 앱 SDK 설정: 안정, 미리 보기 또는 실험적 선택(추가되는 Windows 앱 SDK 버전 결정)
  • TargetFramework update: TargetFramework 지원되는 Windows SDK 버전을 포함하지 않으면 업데이트하라는 메시지가 표시됩니다(예: net10.0-windows10.0.26100.0).
  • 개발자 모드: "개발자 모드"에 대한 메시지가 표시되면 원하는 경우 켤 수 있지만 관리 권한이 필요하다는 점에 유의하세요.

이 명령은 다음을 수행합니다.

  • (필요한 경우) TargetFramework에 있는 .csproj을(를) 지원되는 Windows TFM으로 업데이트합니다.
  • Microsoft.WindowsAppSDK, Microsoft.Windows.SDK.BuildToolsMicrosoft.Windows.SDK.BuildTools.WinApp NuGet 패키지 참조를 .csproj에 추가하세요.
  • Package.appxmanifestAssets 폴더를 앱 ID용으로 생성하세요.

비고

네이티브/C++ 프로젝트와 달리 .NET 흐름은 winapp.yaml 파일을 만들지 않습니다. NuGet 패키지는 . .csproj를 통해 직접 관리됩니다. 복제 후 패키지를 복원하는 데 사용합니다 dotnet restore .

Package.appxmanifest는 표시 이름, 게시자 및 기능과 같은 속성을 추가로 사용자 지정하는 데 사용할 수 있습니다.

패키지가 프로젝트에 추가되었는지 확인하려면 다음을 수행합니다.

dotnet list package

출력에 Microsoft.WindowsAppSDKMicrosoft.Windows.SDK.BuildTools 표시됩니다.

실행 별칭 추가(콘솔 앱용)

콘솔 앱을 빌드하기 때문에 콘솔 출력을 dotnet run 현재 터미널에 유지해야 합니다. 기본적으로 dotnet run는 AUMID 활성화를 통해 패키지된 앱을 시작하며, 새로운 창이 열립니다. 콘솔 앱이 완료되면 창이 즉시 닫혀서 출력이 사라집니다.

이 문제를 해결하려면 매니페스트에 실행 별칭을 추가하고 대신 해당 별칭을 통해 실행 통합을 시작하도록 지시합니다.

UI 앱(WPF, WinForms, WinUI)을 빌드하는 경우 이 단계를 건너뜁니다. 이러한 앱들은 자체 창을 렌더링하므로, 기본 AUMID로 시작하는 것이 적합합니다.

  1. 매니페스트에 실행 별칭을 추가합니다.

    winapp manifest add-alias
    

    uap5:ExecutionAlias Package.appxmanifest은 (프로젝트의 exe 이름을 기본값으로 하여) 터미널에서 이름으로 앱을 시작할 수 있도록 추가됩니다.

  2. 통합에 별칭을 사용하도록 dotnet run를 지시합니다. 다음을 열고 dotnet-app.csproj 내부에 <PropertyGroup> 추가하거나 필요한 경우 새로 <PropertyGroup> 만듭니다.

    <WinAppRunUseExecutionAlias>true</WinAppRunUseExecutionAlias>
    

    이 속성 집합 dotnet run 을 사용하면 실행 별칭을 통해 앱을 시작하고 콘솔 출력을 인라인으로 볼 수 있도록 현재 터미널의 stdin/stdout/stderr를 상속합니다.

5. ID를 사용하여 디버그

winapp init 프로젝트에 Microsoft.Windows.SDK.BuildTools.WinApp NuGet 패키지를 추가했기 때문에 간단히 실행할 수 있습니다.

dotnet run

그러면 내부적으로 winapp run이 자동으로 호출됩니다. 즉, 느슨한 레이아웃 패키지를 만들고, Windows에 등록하고, 완전한 패키지 ID로 앱을 시작합니다.

비고

패키지 원본에 대한 NuGet 취약성 경고(NU1900)가 표시 될 수 있습니다. 이는 무시해도 안전하며 빌드에 영향을 주지 않습니다.

다음과 유사한 결과가 표시됩니다.

Package Family Name: dotnet-app_12345abcde

그러면 앱이 유효한 패키지 ID로 실행되고 있는지 확인합니다.

대안: 수동 winapp run

NuGet 패키지를 사용하지 winapp init 않았거나 제거한 경우 수동으로 빌드하고 실행할 수 있습니다.

dotnet build -c Debug
winapp run .\bin\Debug\net10.0-windows10.0.26100.0

NuGet 패키지를 다시 추가하려면 dotnet add package Microsoft.Windows.SDK.BuildTools.WinApp --prerelease

팁 (조언)

자동 dotnet run 통합을 사용하지 않도록 설정하려면 .csproj<EnableWinAppRunSupport>false</EnableWinAppRunSupport>을 추가하십시오. 사용자 지정 옵션은 dotnet run 지원 문서를 참조하세요.

대안: 스파스 패키지 ID

특히 스파스 패키지 동작(파일을 복사하지 않는 ID)이 필요한 경우 대신 사용할 create-debug-identity 수 있습니다. 그러면 느슨한 레이아웃을 만드는 대신 exe를 가리키는 스파스 패키지가 등록됩니다.

winapp create-debug-identity .\bin\Debug\net10.0-windows10.0.26100.0\dotnet-app.exe

그런 다음 실행 파일을 직접 실행합니다(파일을 다시 빌드/덮어쓸 수 있으므로 사용하지 dotnet run 마세요.)

.\bin\Debug\net10.0-windows10.0.26100.0\dotnet-app.exe

대안: 수동 MSBuild 타겟

NuGet 패키지를 사용하지 않으려는 경우 디버그 빌드 후에 실행되는 create-debug-identity 사용자 지정 MSBuild 대상을 추가할 수 있습니다. .csproj 파일의 끝, 닫는 </Project> 태그 바로 앞에 이 항목을 추가합니다.

  <!-- Automatically apply debug identity after Debug builds -->
  <Target Name="ApplyDebugIdentity" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
    <Exec Command="winapp create-debug-identity &quot;$(TargetDir)$(TargetName).exe&quot;" 
          WorkingDirectory="$(ProjectDir)" 
          IgnoreExitCode="false" />
  </Target>

이 구성 dotnet build 을 사용하면 디버그 ID를 적용하고 실행 파일을 직접 실행할 수 있습니다. 참고하십시오: dotnet run가 ID 정보를 다시 생성하고 덮어쓸 수 있으므로, 빌드 후 exe 파일을 수동으로 실행하십시오.

팁 (조언)

고급 디버깅 워크플로(디버거 연결, IDE 설정, 시작 디버깅)는 디버깅 가이드를 참조하세요.

이를 건너뛰는 경우: ID가 적용되는 시기를 명시적으로 제어하거나 대부분의 개발 주기에 ID가 필요하지 않은 코드를 작업하는 경우 위의 수동 접근 방식이 더 간단할 수 있습니다.

6. Windows 앱 SDK 사용(선택 사항)

이 Windows 앱 SDK 통해 SDK에서 제공하는 기본 Windows 이외의 최신 Windows API(예: 알림 시스템, 창 API, 앱 수명 주기 관리 및 디바이스 내 AI)에 액세스할 수 있습니다. 앱에 이러한 기능이 필요한 경우 이 단계를 수행합니다. 배포에 패키지 ID만 필요한 경우 7단계로 건너뛸 수 있습니다.

winapp init(4단계)를 실행한 경우 Microsoft.WindowsAppSDK 이미 .csproj 대한 NuGet 패키지 참조로 추가되었습니다. dotnet list package로 확인할 수 있습니다. init 중에 SDK 설정을 건너뛰거나 수동으로 추가해야 하는 경우 다음을 실행합니다.

dotnet add package Microsoft.WindowsAppSDK

Program.cs 업데이트

Program.cs 전체 내용을 Windows 앱 런타임 버전 검사를 추가하는 다음 코드로 바꿉니다.

using Windows.ApplicationModel;

class Program
{
    static void Main(string[] args)
    {
        try
        {
            var package = Package.Current;
            var familyName = package.Id.FamilyName;
            Console.WriteLine($"Package Family Name: {familyName}");
            
            // Get Windows App Runtime version using the API
            var runtimeVersion = Microsoft.Windows.ApplicationModel.WindowsAppRuntime.RuntimeInfo.AsString;
            Console.WriteLine($"Windows App Runtime Version: {runtimeVersion}");
        }
        catch (InvalidOperationException)
        {
            // Thrown when app doesn't have package identity
            Console.WriteLine("Not packaged");
        }
    }
}

빌드 및 실행

Windows 앱 SDK 사용하여 애플리케이션을 다시 빌드하고 실행합니다. WinAppSDK를 추가했으므로 런타임 종속성을 추가하도록 winapp ID에 다시 등록해야 합니다. WinApp NuGet 패키지를 추가한 경우(권장) 실행 dotnet run하기만 하면 됩니다. 그렇지 않으면 (프로젝트 이름을 dotnet-app 으로 바꾸기):

dotnet build -c Debug
winapp run .\bin\Debug\net10.0-windows10.0.26100.0

이제 다음과 같은 출력이 표시됩니다.

Package Family Name: dotnet-app.debug_12345abcde
Windows App Runtime Version: 8000.770.947.0

Windows 앱 SDK NuGet 패키지에는 다음을 포함하여 최신 Windows API에 액세스하는 데 필요한 모든 어셈블리가 포함되어 있습니다.

  • 알림 및 라이브 타일
  • 창 및 앱 수명 주기
  • 푸시 알림
  • 그리고 더 많은 Windows 앱 SDK 구성 요소

고급 Windows 앱 SDK 사용은 Windows 앱 SDK 설명서 참조하세요.

7. MSIX를 사용한 패키지

앱을 배포할 준비가 되면 동일한 매니페스트를 사용하여 MSIX로 패키지할 수 있습니다.

릴리스용 빌드

먼저 최적의 성능을 위해 릴리스 모드에서 애플리케이션을 빌드합니다.

dotnet build -c Release

비고

NuGet 취약성 경고(NU1900)가 표시 될 수 있습니다. 무시해도 안전하며 빌드 출력에 영향을 주지 않습니다.

개발 인증서 생성

패키징하기 전에 서명을 위한 개발 인증서가 필요합니다. 아직 생성하지 않은 경우 생성합니다.

winapp cert generate --if-exists skip

서명 및 패키징

이제 패키지하고 서명할 수 있습니다. 팩 명령을 빌드 출력 폴더로 가리키고, dotnet-app 및 TFM 경로를 프로젝트의 값으로 교체합니다.

# package and sign the app with the generated certificate
winapp pack .\bin\Release\net10.0-windows10.0.26100.0 --manifest .\Package.appxmanifest --cert .\devcert.pfx 

참고: 명령은 pack 현재 디렉터리의 Package.appxmanifest를 자동으로 사용하고 패키징하기 전에 대상 폴더에 복사합니다. 생성된 .msix 파일은 현재 디렉터리에 있습니다.

인증서 설치

MSIX 패키지를 설치하려면 개발 인증서를 설치해야 합니다. 관리자 권한으로 다음 명령을 실행합니다.

winapp cert install .\devcert.pfx

설치 및 실행

생성된 *.msix 파일을 두 번 클릭하여 패키지를 설치합니다.

이제 다음을 입력하여 터미널의 어디에서나 앱을 실행할 수 있습니다.

dotnet-app

"패키지 패밀리 이름" 출력이 표시되면, 설치되어 있고 식별자로 실행 중임을 확인할 수 있습니다.

팁 (조언)

앱을 다시 패키지해야 하는 경우(예: 코드 변경 후), winapp pack를 다시 실행하기 전에 Package.appxmanifest을 증가시키십시오. Windows 설치된 패키지를 업데이트하려면 더 높은 버전 번호가 필요합니다.

  1. 배포할 준비가 되면 사용자가 자체 서명된 인증서를 설치할 필요가 없도록 인증 기관의 코드 서명 인증서로 MSIX에 서명할 수 있습니다.
  2. Microsoft Store 제출 전에 서명할 필요 없이 MSIX에 서명합니다.
  3. 지원하는 각 아키텍처(x64, Arm64)에 대해 하나씩 여러 MSIX 패키지를 만들어야 할 수 있습니다. 플래그를 -r 사용하여 특정 아키텍처를 대상으로 지정합니다. dotnet build 또는 dotnet build -c Release -r win-x64dotnet build -c Release -r win-arm64 .

MSIX 패키징 자동화(선택 사항)

릴리스 빌드의 일부로 MSIX 패키징을 자동화하려면 이 대상을 .csproj 파일에 추가합니다(디버그 ID 대상과 함께 추가할 수 있음).

  <!-- Automatically package as MSIX after Release builds -->
  <Target Name="PackageMsix" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
    <!-- Package and sign directly from build output -->
    <Exec Command="winapp pack &quot;$(TargetDir.TrimEnd('\'))&quot; --cert &quot;$(ProjectDir)devcert.pfx&quot;" 
          WorkingDirectory="$(ProjectDir)" 
          IgnoreExitCode="false" />
  </Target>

이 구성에서는 다음을 수행합니다.

  • 릴리스 모드(dotnet build -c Release)에서 빌드하면 MSIX 패키지가 자동으로 생성됩니다.
  • MSIX가 패키지되고 개발 인증서로 서명됩니다.
  • 최종 .msix 파일은 프로젝트의 루트에 있습니다.

조건을 PackagedRelease수정하여 사용자 지정 구성(예: '$(Configuration)' == 'PackagedRelease')을 만들 수도 있습니다.

다음 단계

  • winget을 통한 배포: MSIX를 Windows 패키지 관리자 커뮤니티 리포지토리
  • Microsoft Store에 게시: winapp store를 사용하여 패키지를 제출하십시오.
  • CI/CD 설정: setup-WinAppCli GitHub 작업을 사용하여 파이프라인에서 패키징 자동화
  • Explore Windows API들: 패키지 ID로, 이제 알림, 기기 내 AI 및 기타 ID에 의존하는 API을 사용할 수 있습니다.