Visual Studio 2019 で UWP や Desktop Bridge アプリのパッケージングをすると msix 形式になってますね。 UWP 自体は VS 2017 の頃からいつからか忘れましたが多分 msix になってたけど Desktop Bridge のほうの Windows パッケージ プロジェクトは appx だった気がする?
さて、1 つ前くらいの Windows 10 から .appinstaller
という形式のファイルでインストールするとアプリケーションの自動更新に対応できるようになってました。
ただ、勝手にいつの間にかアップデートされてるという感じの挙動でした。
Windows 10 1809 以降は細かな制御も可能になっています。例えば
- 確認がある場合に更新をするかユーザーに確認する
- 強制的に更新を適用するように強要する
- アップデートだけではなくダウングレードも許可する
詳細は以下を確認してください。
やってみよう
msix なので、とりあえず UWP でやってみようと思いますが、.NET Framework や .NET Core の WPF/WinForms アプリもパッケージングしてしまえば同じなので今からやることは Desktop Bridge アプリでも可能です。 UWP アプリを作って画面に適当な TextBlock を置きます。
<Pagex:Class="UpdateSampleApp.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:UpdateSampleApp"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><Grid><TextBlock Style="{StaticResource HeaderTextBlockStyle}"HorizontalAlignment="Center"VerticalAlignment="Center"Text="最初のバージョン" /></Grid></Page>
プロジェクトの右クリックメニューからストア→アプリパッケージの作成でサイドロード用のパッケージを作成します。
ウィザードを進めていくと、アプリパッケージを実際に配置する場所のパス(URL やファイルパスなど) を指定するような画面が出てくるのでさくっと入れます。 私は AppPackages フォルダーの直下をとりあえず指定しました。とりあえず試すだけなら、出力先をそのまま書くのが楽ちん。
以下のような感じで出力されます。
そして、おもむろに .appinstaller
ファイルをエディターで開きます。残念ながら更新の制御の設定は、ツールサポートがまだないので手書きです。
基本的に UpdateSettings タグに以下のようなものを書きます。xmlns
<!-- AppInstaller タグの xmlns の最後を 2017/2 から 2018 にしてください --><UpdateSettings><OnLaunch HoursBetweenUpdateChecks="0"ShowPrompt="true"UpdateBlocksActivation="true" /><ForceUpdateFromAnyVersion>true</ForceUpdateFromAnyVersion></UpdateSettings>
ShowPrompt を追加すると更新があるときにダイアログが出ます。ユーザーは更新をせずに起動することが可能です。(次回起動時に自動更新される) UpdateBlocksActivation を追加すると更新を強制できます。
ForceUpdateFromAnyVersion を追加するとダウングレードが可能になります。順にみていきましょう。
ShowPrompt
xmlns を 2018 にして ShowPrompt を true にします。
<UpdateSettings><OnLaunch HoursBetweenUpdateChecks="0"ShowPrompt="true" /></UpdateSettings>
そして、index.html からインストールをします。事前に証明書(.cer
)をローカルマシンの信頼されたルート証明機関に入れておきましょう。以下の場所からダウンロードできます。
アプリを取得するボタンを押すとインストールが始まって起動します。
適当にアプリを更新します。TextBlock のテキストを「次のバージョン」にしました。 同じ手順でアプリケーションをサイドロード用のパッケージにパッケージングします。
そして同じように .appinstaller
を書き換えて ShowPrompt を追加します。
そしてアプリを起動すると以下のような画面が表示されます。
ローカライズが非常に残念なのですが、ちょっとちゃんとフィードバックしておきます。 更新完了が Finish updating で営業中が Open now の翻訳になります…。営業中は予想外でした。
更新完了を押すと更新されて起動します。営業中を押すとアプリが更新されずに起動しますが裏で更新が行われます。
UpdateBlocksActivation
これを追加すると更新を強制出来ます。適当にアプリを更新して .appinstalelr
を以下のようにします。名前空間を 2018 に変更するのも忘れずに。
<UpdateSettings><OnLaunch HoursBetweenUpdateChecks="0"ShowPrompt="true"UpdateBlocksActivation="true" /></UpdateSettings>
こんな感じのダイアログが表示されます。
更新を押すと更新されて、キャンセルを押すと起動しないけど裏で更新されます。(結局どっち押しても最終的には更新されます)
ForceUpdateFromAnyVersion
さて、重大なバグがあって過去のバージョンに戻したいとしましょう。
.appinstaller
に ForceUpdateFromAnyVersion を追加してファイル内のバージョンを表す数字を全部過去の任意のバージョンにします。
- AppInstaller タグの Version 属性
- MainBundle タグの Version 属性
- MainBundle タグの Uri 属性を古いバージョンのファイルへのパスに変更
- Dependencies タグの Package タグの Uri を古いバージョンのファイルへのパスに変更
この状態でアプリを起動しても普通に起動するのですが、編集した .appinstaller
ファイルをダブルクリックするか Web サイトのリンククリックで起動すると以下のようなダイアログが出てきます。
更新を押すと古いバージョンに更新されます。ForceUpdateFromAnyVersion を設定していないと過去のバージョンへの更新は出来ません。
まとめ
ClickOnce を置き換えてもいいかな?ってくらいの機能が揃ってきたような気がする…? Windows 10 のバージョンの問題さえクリアすればですが…。