MSIX로 앱을 배송할 때 프로그래밍 방식으로 애플리케이션 업데이트를 시작할 수 있습니다. 스토어 외부에 앱을 배포하는 경우 서버에서 새 버전의 앱을 확인하고 새 버전을 설치하기만 하면 됩니다. 업데이트를 적용하는 방법은 앱 설치 관리자 파일을 사용하여 앱 패키지를 배포하는지 여부에 따라 달라집니다. 코드에서 업데이트를 적용하려면 앱 패키지가 packageManagement
기능을 선언해야 합니다. 게시자 간 시나리오에서는 이 기능이 필요하지만, 사용자 자신의 앱을 관리하는 경우 기능을 선언하지 않아도 작동합니다.
이 문서에서는 패키지 매니페스트에서 기능을 선언 packageManagement
하는 방법과 코드에서 업데이트를 적용하는 방법을 보여 주는 예제를 제공합니다. 첫 번째 섹션에서는 앱 설치 관리자 파일을 사용하는 경우 이 작업을 수행하는 방법을 살펴보고, 두 번째 섹션에서는 앱 설치 관리자 파일을 사용하지 않을 때 이를 수행하는 방법에 대해 설명합니다. 마지막 섹션에서는 업데이트가 적용된 후 앱이 다시 시작되는지 확인하는 방법을 살펴봅니다.
패키지 매니페스트에 PackageManagement 기능 추가
API를 PackageManager
사용하려면 앱이 packageManagement
에서 제한된 기능을 선언해야 합니다.
<Package>
...
<Capabilities>
<rescap:Capability Name="packageManagement" />
</Capabilities>
...
</Package>
앱 설치 관리자 파일을 사용하여 배포된 패키지 업데이트
앱 설치 관리자 파일을 사용하여 애플리케이션을 배포하는 경우 수행하는 코드 기반 업데이트는 앱 설치 관리자 파일 API를 사용해야 합니다. 이렇게 하면 일반 앱 설치 관리자 파일 업데이트가 계속 작동합니다. 코드에서 앱 설치 관리자 기반 업데이트를 관장하려면 PackageManager.AddPackageByAppInstallerFileAsync 또는 PackageManager.RequestAddPackageByAppInstallerFileAsync를 사용할 수 있습니다. Package.CheckUpdateAvailabilityAsync API를 사용하여 업데이트를 사용할 수 있는지 확인할 수 있습니다. 다음은 예제 코드입니다.
using Windows.Management.Deployment;
public async void CheckForAppInstallerUpdatesAndLaunchAsync(string targetPackageFullName, PackageVolume packageVolume)
{
// Get the current app's package for the current user.
PackageManager pm = new PackageManager();
Package package = pm.FindPackageForUser(string.Empty, targetPackageFullName);
PackageUpdateAvailabilityResult result = await package.CheckUpdateAvailabilityAsync();
switch (result.Availability)
{
case PackageUpdateAvailability.Available:
case PackageUpdateAvailability.Required:
//Queue up the update and close the current instance
await pm.AddPackageByAppInstallerFileAsync(
new Uri("https://trial3.azurewebsites.net/HRApp/HRApp.appinstaller"),
AddPackageByAppInstallerOptions.ForceApplicationShutdown,
packageVolume);
break;
case PackageUpdateAvailability.NoUpdates:
// Close AppInstaller.
await ConsolidateAppInstallerView();
break;
case PackageUpdateAvailability.Unknown:
default:
// Log and ignore error.
Logger.Log($"No update information associated with app {targetPackageFullName}");
// Launch target app and close AppInstaller.
await ConsolidateAppInstallerView();
break;
}
}
앱 설치 관리자 파일 없이 배포된 패키지 업데이트
서버에서 업데이트 확인
앱 설치 관리자 파일을 사용하여 앱 패키지를 배포 하지 않는 경우 첫 번째 단계는 새 버전의 애플리케이션을 사용할 수 있는지 직접 확인하는 것입니다. 다음 예제에서는 서버의 패키지 버전이 앱의 현재 버전보다 큰지 확인합니다(이 예제에서는 데모를 위해 테스트 서버를 참조).
using Windows.Management.Deployment;
//check for an update on my server
private async void CheckUpdate(object sender, TappedRoutedEventArgs e)
{
WebClient client = new WebClient();
Stream stream = client.OpenRead("https://trial3.azurewebsites.net/HRApp/Version.txt");
StreamReader reader = new StreamReader(stream);
var newVersion = new Version(await reader.ReadToEndAsync());
Package package = Package.Current;
PackageVersion packageVersion = package.Id.Version;
var currentVersion = new Version(string.Format("{0}.{1}.{2}.{3}", packageVersion.Major, packageVersion.Minor, packageVersion.Build, packageVersion.Revision));
//compare package versions
if (newVersion.CompareTo(currentVersion) > 0)
{
var messageDialog = new MessageDialog("Found an update.");
messageDialog.Commands.Add(new UICommand(
"Update",
new UICommandInvokedHandler(this.CommandInvokedHandler)));
messageDialog.Commands.Add(new UICommand(
"Close",
new UICommandInvokedHandler(this.CommandInvokedHandler)));
messageDialog.DefaultCommandIndex = 0;
messageDialog.CancelCommandIndex = 1;
await messageDialog.ShowAsync();
} else
{
var messageDialog = new MessageDialog("Did not find an update.");
await messageDialog.ShowAsync();
}
}
비고
targetPackageFileName
는 패키지 앱의 전체 이름을 나타냅니다. (예: Contoso.HeadTrax_1.0.0.0_x64__PublisherHash)
업데이트 적용
업데이트를 사용할 수 있다고 확인하면 AddPackageAsync API를 사용하여 다운로드 및 설치를 위해 큐에 대기할 수 있습니다. 또한 기본 패키지가 디바이스에 이미 설치되어 있는 한 선택적 패키지를 설치하는 데도 작동합니다. 업데이트는 다음에 앱이 종료될 때 적용됩니다. 앱을 다시 시작하면 사용자가 새 버전을 사용할 수 있습니다. 다음은 예제 코드입니다.
// Queue up the update and close the current app instance.
private async void CommandInvokedHandler(IUICommand command)
{
if (command.Label == "Update")
{
PackageManager packagemanager = new PackageManager();
await packagemanager.AddPackageAsync(
new Uri("https://trial3.azurewebsites.net/HRApp/HRApp.msix"),
null,
AddPackageOptions.ForceApplicationShutdown
);
}
}
업데이트 후 자동으로 앱 다시 시작
애플리케이션이 UWP 앱인 경우 업데이트를 적용할 때 AddPackageByAppInstallerOptions.ForceApplicationShutdown 또는 AddPackageOptions.ForceTargetAppShutdown을 전달하면 종료 + 업데이트 후에 앱이 다시 시작되도록 예약해야 합니다. UWP가 아닌 앱의 경우 업데이트를 적용하기 전에 RegisterApplicationRestart 를 호출해야 합니다.
앱이 종료되기 전에 RegisterApplicationRestart를 호출해야 합니다. 다음은 interop 서비스를 사용하여 C#에서 네이티브 메서드를 호출하는 예제입니다.
// Register the active instance of an application for restart in your Update method
uint res = RelaunchHelper.RegisterApplicationRestart(null, RelaunchHelper.RestartFlags.NONE);
C#에서 네이티브 RegisterApplicationRestart 메서드를 호출하는 도우미 클래스의 예:
using System;
using System.Runtime.InteropServices;
namespace MyEmployees.Helpers
{
class RelaunchHelper
{
#region Restart Manager Methods
/// <summary>
/// Registers the active instance of an application for restart.
/// </summary>
/// <param name="pwzCommandLine">
/// A pointer to a Unicode string that specifies the command-line arguments for the application when it is restarted.
/// The maximum size of the command line that you can specify is RESTART_MAX_CMD_LINE characters. Do not include the name of the executable
/// in the command line; this function adds it for you.
/// If this parameter is NULL or an empty string, the previously registered command line is removed. If the argument contains spaces,
/// use quotes around the argument.
/// </param>
/// <param name="dwFlags">One of the options specified in RestartFlags</param>
/// <returns>
/// This function returns S_OK on success or one of the following error codes:
/// E_FAIL for internal error.
/// E_INVALIDARG if rhe specified command line is too long.
/// </returns>
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
internal static extern uint RegisterApplicationRestart(string pwzCommandLine, RestartFlags dwFlags);
#endregion Restart Manager Methods
#region Restart Manager Enums
/// <summary>
/// Flags for the RegisterApplicationRestart function
/// </summary>
[Flags]
internal enum RestartFlags
{
/// <summary>None of the options below.</summary>
NONE = 0,
/// <summary>Do not restart the process if it terminates due to an unhandled exception.</summary>
RESTART_NO_CRASH = 1,
/// <summary>Do not restart the process if it terminates due to the application not responding.</summary>
RESTART_NO_HANG = 2,
/// <summary>Do not restart the process if it terminates due to the installation of an update.</summary>
RESTART_NO_PATCH = 4,
/// <summary>Do not restart the process if the computer is restarted as the result of an update.</summary>
RESTART_NO_REBOOT = 8
}
#endregion Restart Manager Enums
}
}