ストア以外の発行済みアプリ パッケージをコードから更新する

アプリを MSIX として配布する場合は、プログラムでアプリケーションの更新を開始できます。 ストアの外部にアプリをデプロイする場合は、サーバーで新しいバージョンのアプリを確認し、新しいバージョンをインストールする必要があります。 更新プログラムを適用する方法は、アプリケーション ファイルを使用してアプリ パッケージをデプロイするかどうかアプリ インストーラーによって異なります。 コードから更新プログラムを適用するには、アプリ パッケージで 機能を宣言する必要 packageManagement があります。

この記事では、パッケージ マニフェストで機能を宣言する方法と、コードから更新プログラムを適用する方法を示 packageManagement す例を示します。 最初のセクションでは、アプリ インストーラー ファイルを使用している場合にこれを行う方法を確認します。2 番目のセクションでは、アプリ インストーラーファイルを使用しない場合にこれを行う方法について説明します。 最後のセクションでは、更新プログラムが適用された後にアプリが再起動される方法を確認します。

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();
    }
}

更新プログラムを適用する

更新プログラムを使用できると判断した後は 、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 を呼び出す必要があります。 次に、相互運用サービスを使用して 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

    }
}