デスクトップ・ブリッジを使ってJavaアプリをUWPアプリにしよう

Java アプリをデスクトップ ブリッジ UWP アプリとして.appx パッケージにまとめると Microsoft Store を通して Java アプリを配布できるようになります。

本記事では Desktop App Converter ではなく MakeAppx コマンドを使って Java アプリを UWP アプリ パッケージ化する方法を解説します。

Microsoft Store って何?

Microsoft Store とはマイクロソフトが展開しているアプリ ストアです。有償アプリだけでなく無償アプリの配布にも使えるアプリ配信プラットフォームです。当初は Windows Store という名前でしたが 2017 年に Microsoft Store という名前に変わりました。Google Android 向けに展開している Google Play アップルが iOS 向けに展開している App Store のマイクロソフト版と言ったところです。

Microsoft Store では UWP Universal Windows Platform アプリを配信することができます。

マイクロソフトが思っていたほど Microsoft Store は盛り上がらなかったようです。マイクロソフトは 開発者登録料を 19 ドルに値下げしたり 年間更新料を無料化したりと Microsoft Store のアプリを拡充するための施策を打ち出してきました。

さらにマイクロソフトはアプリを拡充するためにいくつかのブリッジ プロジェクトを始めました。

Project “Astoria”

Project “Astoria” は Android アプリ apk を変換して Windows Phone Windows 10 で動かせるようにするという 無謀な プロジェクトでした。このプロジェクトは上手くいかなかったようですでに中止されています。

Project “Islandwood”

Project “Islandwood” は iOS アプリを Windows で動かせるようにするプロジェクトです。 “Astoria” が apk をエミュレーションで動かそうとしていたのに対して “Islandwood” では Xcode プロジェクトを Visual Studio にインポートして UWP アプリとしてビルドし直すというアプローチのようです。Visual Studio Objective-C 使えるんですね…。

Project “Westminster”

Project “Westminster” は Web アプリを変換して UWP アプリにするプロジェクトです。

Project “Centennial”

Project “Centennial” は Win32 や.NET で作られた既存のデスクトップ アプリを UWP パッケージ化するプロジェクトです。このプロジェクトの成果 正式名称が Desktop Bridge です。Desktop Bridge によって Java アプリの UWP Microsoft Store への登録 そして配布が可能になりました。

Desktop Bridge

Desktop Bridge Project “Astoria” や Project “Islandwood” とは性質が異なります。エミュレーションでアプリを実行する “Astoria” なんて上手くいくはずがないと多くの開発者が思っていましたし “Islandwood” もコード修正が必要になるなど手間がかかる仕組みでした。

ですが Desktop Bridge は違います。Desktop Bridge における UWP 化とは既存アプリケーションを Microsoft Store に登録可能な.appx インストーラー パッケージ としてラッピングすることを指しています。アプリケーションの実行コードを変換することなく 既存のデスクトップ アプリケーションをそのまま実行する仕組みです。Desktop Bridge は安心 確実な UWP 化アプローチと言えます。

ただし UWP としてアプリを実行した場合は 特定のレジストリやフォルダーへのアクセスが禁止されたり別のパスへリダイレクトされるといった動作の違いがあります。これは Windows 7 で導入されたファイルの仮想化に似ています。Windows 7 以降 UAC が有効化されていて管理者としてプログラムを実行していない場合は %ProgramFiles% への書き込みが仮想化によって %LOCALAPPDATA%¥VirtualSotre¥Program Files にリダイレクトされるようになりました。UWP でも似たようなリダイレクトが行われます。

UWP 化したデスクトップ アプリケーションがシステムフォルダーにアクセスした場合にどこへリダイレクトされるのかについては パッケージ デスクトップ アプリケーションの内側 が詳しいです。

既存のアプリケーションを Desktop Bridge UWP パッケージ化する方法はいくつかあります。

Desktop App Converter

Desktop App Converter DAC Desktop Bridge UWP パッケージを作成するツールの 1 つです。この DAC はかなり大げさな仕組みのツールです。Desktop App Converter Base Images と呼ばれるイメージファイル 3.5GB 以上! も必要になります。

このコンバーターは コンバーターのダウンロードに含まれるクリーンな状態の基本イメージを使って 分離された Windows 環境でデスクトップ インストーラーを実行します。デスクトップ インストーラーが作成するすべてのレジストリとファイルシステムの I/O をキャプチャし 出力の一部としてパッケージ化します。

なるほど。基本イメージと呼ばれる仮想マシン上で既存アプリケーションのインストーラーを実際に動かして インストーラーがどのようにレジストリやファイルを書き換え 配置するかを調べるわけですね。

既存アプリケーションのインストーラーがインストール過程でレジストリを書き換えたり システム領域に共有 DLL を配置するような複雑な構成の場合には こういった方法が必要かもしれません。

ですが xcopy deployment と呼ばれるようなフォルダーをまるごとコピーするだけで実行できるシンプルな構成のアプリケーションであれば インストーラーがどのような I/O をするのかキャプチャをする必要もないはずです。

MakeAppx

MakeAppx はパッケージマニフェストファイル AppxManifest.xml から Desktop Bridge UWP パッケージを作成するコマンドラインツールです。

フォルダーをまるごとコピーするだけで使えるアプリケーションの場合は Desktop App Converter DAC を使わずに MakeAppx コマンドで Desktop Bridge UWP パッケージを作るほうが簡単で手間が掛かりません。

今回は MakeAppx コマンドを使って Java アプリを Desktop Bridge UWP パッケージにしていきます。

Windows 10 SDK をインストールする

Desktop Bridge 化に必要な MakeAppx コマンドは Windows 10 SDK に含まれています。以下のサイトから Windows 10 SDK のインストーラーをダウンロードします。

https://developer.microsoft.com/ja-jp/windows/downloads/windows-10-sdk

ダウンロードした winsdksetup.exe を実行します。

Windows 10 SDK をインストールする場所は変更せずに既定値のまま Next を押します。

問題が発生したときに匿名データをマイクロソフトに送信してもよいか?と聞かれます。yes no どちらを選択しても構いません。Next を押して次に進みます。

ライセンスが表示されます。ライセンスを読んで同意する場合は Accept を押します。

インストールする機能を選択する画面が表示されます。既定では すべての機能にチェックが入っています。ディスクの空き容量に余裕があれば そのまま install を押しても構いません。

ディスク使用量を節約したい場合には不要な機能のチェックを外して必要な機能のみをインストールすることもできます。少なくとも以下の 4 つの機能をインストールしてください。

  •  Windows SDK Signing Tools for Desktop Apps
  •  Windows SDK for UWP Managed Apps
  •  Windows SDK for UWP C++ Apps
  •  Windows SDK for Desktop C++ x86 Apps

MakeAppx コマンドを使ってパッケージを作成するだけであれば Windows SDK Signing Tools for Desktop Apps Windows SDK for UWP Managed Apps 2 つの機能を選択するだけでも十分なのですが この 2 つの機能を選択しただけでは PKCS#12 pfx 証明書を作成するための pvk2pfx.exe がインストールされません。後でパッケージに署名することもありますので pvk2pfx.exe も使えるようにしておきましょう。Windows SDK for Desktop C++ x86 Apps の機能を選択すると pvk2pfx.exe がインストールされます。

install を押すとインストールが開始されます。時間がかかりますのでしばらく待ちましょう。

インストールが完了したら Close を押します。

これで UWP パッケージ作成に必要なコマンドはインストールされましたが コマンドプロンプトを起動しただけでは PATH が通っていないのでコマンドが使えません。

PATH に以下の場所を追加します。フォルダー名にバージョン番号が含まれているのでバージョンによって場所が変わるかもしれません。適宜 読み替えてください

  • C:¥Program Files (x86)¥Windows Kits¥10¥bin¥10.0.17763.0¥x86

もしくは以下の ZIP ファイルをダウンロードして適当なフォルダーに展開してください。

ZIP ファイルに入っている AppxConsole.bat を実行すると MakeAppx.exe MakePri.exe pvk2pfx.exe PATH が通った状態のコマンドプロンプトが起動します。

Java アプリを用意する

UWP パッケージ化する Java アプリを用意します。

前回の記事 OpenJDK Java アプリ配布パッケージを作る でフォルダーをまるごとコピーするだけで実行できる Java アプリを exewrap で作成しましたので 今回もこれをサンプルとして使います。

サンプルプログラムは C:¥temp¥fx-sample にコピーしておきました。

アイコンを用意する

UWP パッケージ .appx に埋め込むアイコン画像を用意しておきましょう。アイコンのサンプル画像 44x44 150x150 を置いておきます。


images.zip

アイコン画像を C:¥temp¥fx-sample¥images に配置しました。次の AppxManifest.xml にアイコン画像の相対パスを記述します。

AppxManifest.xml を作成する

UWP アプリの構成を記述する AppxManifest.xml を作成します。AppxManifest.xml はアプリの名前や作成者 ロゴ画像などを指定する XML ファイルです。雛形となるファイルを元に必要な部分を書き換えていけばいいので難しくはありません。

サンプルプログラムでは以下の AppxManifest.xml を作成しました。AppxManifest.xml C:¥temp¥fx-sample に配置します。

AppxManifest.xml
<?xml version="1.0" encoding="utf-8"?> <Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"> <Identity Name="FxSample" Version="1.0.0.0" Publisher="CN=MyName" ProcessorArchitecture="x64" /> <Properties> <DisplayName>FxSample</DisplayName> <PublisherDisplayName>MyName</PublisherDisplayName> <Description>MyDescription</Description> <Logo>images/duke-44px.png</Logo> </Properties> <Resources> <Resource Language="ja-jp" /> </Resources> <Dependencies> <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.15063.0" MaxVersionTested="10.0.15063.0" /> </Dependencies> <Capabilities> <rescap:Capability Name="runFullTrust"/> </Capabilities> <Applications> <Application Id="fxsample" Executable="fx-sample.exe" EntryPoint="Windows.FullTrustApplication"> <uap:VisualElements DisplayName="MyApp" Description="MyDescription" Square150x150Logo="images/duke-150px.png" Square44x44Logo="images/duke-44px.png" BackgroundColor="#464646" /> </Application> </Applications> </Package>
MinVersion には 10.0.15063.0 以上を指定する必要があります
Windows 10 Anniversary Update 1607, Redstone 1, Build 10.0.14393.0 から Desktop Bridge が利用可能になり Windows 10 Creators Update 1703, Redstone 2, Build 10.0.15063.0 SetDllDirectory 関数が使えるように改善されました。exewrap で作成した Java アプリを UWP 化して実行する場合は SetDllDirectory 関数が必要になるため 最小バージョン MinVersion として 10.0.14393.0 ではなく 10.0.15063.0 以上を指定する必要があります。

パッケージリソースインデックス PRI を作成する

コマンドプロンプトで fx-sample プロジェクトの 1 つ上のフォルダー C:¥temp に移動して次の 2 つのコマンドを実行します。

makepri createconfig /cf priconfig.xml /dq ja-JP

コマンドプロンプト
C:¥temp>makepri createconfig /cf priconfig.xml /dq ja-JP 'Platform (pv)' not specified. Default is Windows 10. Writing PRI config file to priconfig.xml ... Successfully Completed

makepri new /pr fx-sample /cf priconfig.xml /of fx-sample

コマンドプロンプト
C:¥temp>makepri new /pr fx-sample /cf priconfig.xml /of fx-sample Output location of PRI file(s) is detected to be under the project root. If previously generated PRI file(s) are present, these may be re-indexed and lead to unexpected results. Index Pass Completed. Finished building Version: 1.0 Resource Map Name: FxSample Named Resources: 116 Resource File: resources.pri Version: 1.0 Resource Candidates: 116 Successfully Completed

makepri new コマンドを実行するときは /of オプションで resources.pri の出力パスを指定して resources.pri AppxManifest.xml と同じフォルダーに作成されるようにしてください。/of にファイルパスではなくフォルダーパスを指定するとファイル名は自動的に resources.pri になります。

makepri コマンドの実行によって priconfig.xml resources.pri が作成されます。この時点で 以下のようなファイル構成になっています。

  • C:¥temp
    • priconfig.xml
    • fx-sample
      • AppxManifest.xml
      • fx-sample.exe
      • images
        • duke-150px.png
        • duke-44px.png
      • jre-11.0.1
      • resources.pri

resources.pri AppxManifest.xml と同じフォルダーに配置されている必要があります。resources.pri の場所が間違っていると 次の makeappx コマンド実行時に resources.pri の内容が反映されません。

UWP パッケージ .appx を作成する

コマンドプロンプトで fx-sample プロジェクトの 1 つ上のフォルダー C:¥temp に移動して次のコマンドを実行します。

makeappx pack /d fx-sample /p FxSample.appx /o /l /nv

コマンドプロンプト
C:¥temp>makeappx pack /d fx-sample /p FxSample.appx /o /l /nv Microsoft (R) MakeAppx Tool Copyright (C) 2013 Microsoft. All rights reserved. The path (/p) parameter is: "¥¥?¥C:¥temp¥FxSample.appx" The content directory (/d) parameter is: "¥¥?¥C:¥temp¥fx-sample" Enumerating files from directory "¥¥?¥C:¥temp¥fx-sample" Packing 116 file(s) in "¥¥?¥C:¥temp¥fx-sample" (content directory) to "¥¥?¥C:¥temp¥FxSample.appx" (output file name). Memory limit defaulting to 1073506304 bytes. Using "¥¥?¥C:¥temp¥fx-sample¥AppxManifest.xml" as the manifest for the package. Processing "¥¥?¥C:¥temp¥fx-sample¥jre-11.0.1¥bin¥msvcp140.dll" as a payload file. Its path in the package will be "jre-11.0.1¥bin¥msvcp140.dll". (途中省略) Processing "¥¥?¥C:¥temp¥fx-sample¥jre-11.0.1¥release" as a payload file. Its path in the package will be "jre-11.0.1¥release". Package creation succeeded.

末尾に “Package creation succeeded.” と表示されていれば成功です。C:¥temp FxSample.appx が作成されていることが確認できます。

これが Java アプリを Desktop Bridge UWP 化したパッケージ .appx です。

パッケージのインストールを試みるも…

FxSample.appx をダブルクリックするとインストーラーが起動します。

インストール を押してみますが…

インストールに失敗してしまいました。

アプリの開発元に新しいアプリ パッケージを要求してください。このパッケージには 信頼された証明書による署名がありません (0x800B0100)

署名されていない UWP アプリをインストールすることはできません。開発者モードに切り替えることで署名のない UWP アプリをインストールすることもできますが 今回は自己署名証明書でアプリに署名してインストールしてみたいと思います。

自己署名証明書を作成する

証明書の作成には makecert コマンドと pvk2pfx.exe コマンドを使います。

makecert -r -n "CN=MyName" -sv my-sample.pvk my-sample.cer

引数 -n で指定している証明書の名前 CN=MyName AppxManifest.xml Identity 要素 Publisher 属性に指定した値と一致させる必要があるので注意してください。

AppxManifest.xml(Identity要素を抜粋)
<Identity Name="FxSample" Version="1.0.0.0" Publisher="CN=MyName" ProcessorArchitecture="x64" />

コマンドを実行すると秘密鍵(プライベートキー)にパスワードを設定するダイアログが表示されます。今回は 秘密鍵にパスワードを設定しないので None をクリックします。

コマンドプロンプトに “Succeeded” と表示されます。

コマンドプロンプト
C:¥temp>makecert -r -n "CN=MyName" -sv my-sample.pvk my-sample.cer Succeeded

秘密鍵 my-sample.pvk 公開鍵 my-sample.cer が作成されています。

次に 秘密鍵を PKCS#12 個人情報交換ファイル 拡張子.pfx に変換します。

pvk2pfx -pvk my-sample.pvk -spc my-sample.cer -pfx my-sample.pfx

コマンドプロンプト
C:¥temp>pvk2pfx -pvk my-sample.pvk -spc my-sample.cer -pfx my-sample.pfx

これで my-sample.pfx が作成されます。

パッケージに署名する

作成した PKCS#12 個人情報交換ファイル my-sample.pfx パッケージ FxSample.appx に署名します。

signtool sign /a /fd SHA256 /f my-sample.pfx FxSample.appx

コマンドプロンプト
C:¥temp>signtool sign /a /fd SHA256 /f my-sample.pfx FxSample.appx Done Adding Additional Store Successfully signed: FxSample.appx

これでパッケージへの署名が完了しました。

もう一度 FxSample.appx をダブルクリックしてインストールを試みてみます。

このアプリ パッケージ用にインストールされた新しい証明書か 信頼された証明書のある新しいアプリ パッケージが必要です。詳細については システム管理者またはアプリの開発元にお問い合わせください。証明書チェーンを処理しましたが 信頼されていないルート証明書で停止しました (0x800B0109)

再び パッケージのインストールに失敗してしまいましたが エラーメッセージが変わっています。最初は 署名がありません というエラーでしたが 今回は 信頼されていないルート証明書で停止しました というエラーになっています。

パッケージへの署名自体は出来ているようですね。

自作した証明書 my-sample.cer を信頼できるルート証明書としてコンピューターに登録してみましょう。

my-sample.cer をダブルクリックすると証明書の内容が表示されます。この CA ルート証明書は信頼されていません と表示されますが 信頼を有効にするにはこの証明書を信頼されたルート証明機関のストアにインストールしてください と解決方法も教えてくれています。指示に従って 証明書のインストール... をクリックします。

証明書のインポート ウィザードが表示されます。保存場所として ローカル コンピューター を選択して 次へ をクリックします。

証明書をすべて次のストアに配置する を選択して 参照... をクリックします。

証明書ストアの選択ダイアログが表示されるので 信頼されたルート証明機関 を選択 反転表示に して OK をクリックします。

証明書ストアの欄に “信頼されたルート証明機関” と表示されていることを確認して 次へ をクリックします。

最後の確認画面が表示されます。完了 をクリックします。

これで自作の証明書が信頼されたルート証明書として登録されました。

三度目の正直 FxSample.appx をダブルクリックしてインストールを試みます。

インストールがはじまりました!

インストールが完了すると UWP 化した Java アプリが起動しました。インストーラーの最初の画面で 準備ができたら起動 にチェックを入れていたからです

Windows 10 のスタートメニューにもアプリアイコンが追加されています。

無事に Java アプリを Desktop Bridge UWP 化してインストールすることができました。今回は自己署名証明書を使ってのインストールとなりましたが きちんと開発者登録をすれば正規の署名で Microsoft Store を通してアプリを配布することも可能です。

いずれは Microsoft Store への Desktop Bridge UWP アプリの登録手順についても紹介するつもりです。今回のようなサンプルプログラムで登録申請するわけにもいきませんし もう少しちゃんとした Java アプリを作って Microsoft Store への申請に挑戦したいと思います。

この記事を共有しませんか?