ユニバーサル Windows プラットフォーム (UWP) 開発者にとっての .NET ネイティブの意味

※本ブログは Building Apps for Windows ".NET Native – What it means for Universal Windows Platform (UWP) developers”の抄訳です。

.NET ネイティブとは

.NET ネイティブは、Visual Studio 2015 でユニバーサル Windows アプリをビルドするためのプリコンパイル テクノロジです。.NET ネイティブ ツール チェーンは、マネージ IL のバイナリをネイティブのバイナリにコンパイルします。C# または VB を使用するすべてのマネージ ユニバーサル Windows アプリでは、この新しいテクノロジを利用します。アプリケーションはネイティブ コードに自動コンパイルされた後、ユーザーのデバイスに配信されます。.NET ネイティブのしくみを詳しく知りたい場合は、MSDN の記事をご覧ください。

.NET ネイティブは開発者とアプリにどのような影響をもたらすのか

状況によって異なりますが、多くの場合は、アプリの起動が高速になり、パフォーマンスが向上し、消費するシステムリソースが少なく済みます。

  • コールド起動時間のパフォーマンスが最大 60% 向上する
  • ウォーム起動時間のパフォーマンスが最大 40% 向上する
  • アプリをネイティブにコンパイルした場合、メモリの消費量が減少する
  • システムにインストールされているデスクトップ .NET ランタイムへの依存関係がない
  • アプリはネイティブにコンパイルされるため、ネイティブ コードのパフォーマンス (C++ のパフォーマンス) メリットを享受できる
  • 業界をけん引する C# や VB といったプログラミング言語、このようなプログラミング言語に関連付けられているツールが依然として利用できる
  • ビジネス ロジック、組み込みのメモリ管理、例外処理を記述する拡張 API により、.NET では包括的で一貫したプログラミング モデルを使用し続けることができる

マネージ開発エクスペリエンスと C++ パフォーマンスという両方のメリットを享受できます。

デバッグ コンパイル構成とリーリース コンパイル構成の相違点

.NET ネイティブのコンパイルは複雑なプロセスなので、従来の .NET コンパイルと比較すると少し低速になります。前述のメリットは、コンパイル時間と引き換えに享受できます。アプリを起動するたびにネイティブなコンパイルを選択可能ですが、ビルド完了までの待ち時間が長くなります。Visual Studio ツールは、この問題に対処して、できる限りスムーズな開発者エクスペリエンスの実現を目的に設計されています。

“デバッグ” 構成でアプリをビルドして実行するときには、アプリケーションにパッケージ化される CoreCLR に対して IL コードを実行することになります。.NET システムのアセンブリはアプリケーション コードと一緒にパッケージ化され、アプリケーションは Microsoft.NET.CoreRuntime (CoreCLR) パッケージの依存関係を継承することになります。

つまり、高速なコンパイルと配置、リッチなデバッグと診断機能、.NET 開発で使い慣れているその他すべてのツールといった最高の開発エクスペリエンスを享受できます。

“リリース” モードに切り替えると、既定の設定では、アプリは .NET ネイティブ ツール チェーンを使用します。パッケージはネイティブバイナリにコンパイルされるため、パッケージに .NET フレームワークのライブラリを含める必要はありません。また、このパッケージは CoreCLR パッケージとは異なり、インストールされている最新の .NET ネイティブ ランタイムに依存します。そのため、デバイスの .NET ネイティブ ランタイムは、アプリケーションパッケージと必ず互換性が確保されます。

“リリース” モードでローカルのネイティブ コンパイルを使用することで、ユーザーの実行環境に似た環境でアプリケーションをテストできます。開発中には、定期的にアプリケーションをテストすることが重要になります。

経験上、開発中には、このようにして定期的にアプリケーションをテストし、.NET ネイティブ コンパイラに起因する可能性がある問題を特定して修正することを推奨します。多くの場合に問題が発生することはないでしょうが、.NET ネイティブと上手く連動しないものがいくつかあります。その一例は、4 次元以上の配列です。最終的に、ユーザーは .NET ネイティブでコンパイルされたバージョンのアプリケーションをダウンロードすることになるため、開発段階と出荷前には、.NET ネイティブでコンパイルされたバージョンのアプリケーションをテストすることを推奨します。

.NET ネイティブでコンパイルしたバージョンを確実にテストすることに加えて、AnyCPU ビルド構成がなくなっていることに気付く方もいるでしょう。ネイティブ コンパイルはアーキテクチャに依存するため、.NET ネイティブの追加により、AnyCPU は有効なビルド構成ではなくなりました。また、.NET ネイティブの追加により、アプリケーションをパッケージ化するときには 3 つのアーキテクチャ構成 (x86、x64、 ARM) をすべて選択して、できる限り多くのデバイスでアプリケーションを利用できるようにする必要もあります。つまり、これがユニバーサル Windows プラットフォームです。Visual Studio の既定の設定では、画面の指示に従って 3 つのアーキテクチャ構成を選択できます (下図参照)。

1_DotNetNativeCreateAppPackages

図 1 - 既定の設定で 3 つのアーキテクチャがすべて選択されている

とは言うものの、今でも UWP アプリで参照する AnyCPU ライブラリと DLL を作成することは可能です。AnyCPU ライブラリと DLL は、これらのコンポーネントを利用するプロジェクトの構成 (.appx) に基づいて、アーキテクチャ固有のバイナリにコンパイルされます。

.NET ネイティブの追加が開発ワークフローに与えた最後の大きな変化は、Windows ストアに申請できるパッケージの作成方法です。.NET ネイティブの優れた機能の 1 つは、コンパイラをクラウドにホストできることです。Visual Studio でストア パッケージをビルドすると、.appxupload パッケージとサイドローディング用の “test” .appx という 2 つのパッケージが作成されます。.appxupload には、MSIL バイナリだけでなく、アプリで利用する (AppxManifest.xml で参照される) .NET ネイティブ ツールチェーンのバージョンへの明示的な参照が含まれます。.appxupload パッケージは Windows ストアに提出され、まったく同じバージョンの .NET ネイティブ ツールチェーンを使用してコンパイルされます。コンパイラはクラウドでホストされているため、アプリをローカルで再コンパイルすることなく、クラウドで繰り返しコンパイルしてバグを修正できます。

2__DotNetNativePackagesInExplorer

図 2 - .appxupload はストアに提出し、Test フォルダーにはサイドローディングする appx パッケージが含まれている

開発者のワークフローには大きな 2 つの変化があります。1 つ目の変化は、アプリケーション パッケージのリビジョン番号 (4 つ目の番号) にアクセスできないことです。何らかの理由でアプリ パッケージをクラウドで再コンパイルする場合にアプリパッケージで繰り返し処理を行うための方法として、Windows ストアではリビジョン番号が予約されています。ただし、他の 3 つの番号は操作できますので、ご心配には及びません。

2 つ目の変化は、Windows ストアにアップロードするパッケージに注意しなければならなくなったことです。Windows ストアではネイティブなコンパイルが実行されますが、ローカルの .NET ネイティブ コンパイラで生成したネイティブなバイナリを Windows ストアにアップロードすることはできません。このプロセスは、Visual Studio のワークフローに従って行うため、適切なパッケージを選択できます。

3__DotNetNativeCreatePackageForStore

図 3 - [はい] を選択して Windows ストアにアップロードする

アプリ パッケージの作成ウィザードを使用してパッケージを作成するときには、Windows ストアにアップロードするパッケージを作成するかどうかを確認するメッセージで [はい] を選択してください。また、[アプリ バンドルの生成] オプションで [常に行う] を選択することを推奨します。このオプションを選択すると、アップロード準備が完了した単一の .appxupload ファイルが作成されます。Windows ストアにアップロードするパッケージ作成の詳しい説明については、「Windows 10 のユニバーサル Windows アプリをパッケージ化する」を参照してください。

.NET ネイティブの追加による開発ワークフローへの主な変更点は以下のとおりです。

  • “リリース” 構成を使用して定期的にアプリケーションをテストする
  • パッケージのリビジョン番号が 0 になっていることを確認する。Visual Studio でパッケージのリビジョン番号を変更することはできないが、テキスト エディターでリビジョン番号を変更していないことを確認する。
  • ストアに申請するパッケージの作成で生成した .appxupload のみをアップロードする。UWP の .appx をアップロードすると、エラーが表示され、ストアによって拒否される。

.NET ネイティブを利用するためのヒント

.NET ネイティブによる問題が発生した可能性がある場合、問題のデバッグに役立つテクニックがあります。リリース構成は、既定の設定でデバッグで使用する一部の成果物がない状態にコードを最適化します。そのため、リリース構成をデバッグしようとすると何らかの問題が発生します。この場合にできることは、カスタム構成を作成して、カスタム構成で .NET ネイティブ ツールチェーンを利用できるようにすることです。コードは最適化しないようにしてください。詳細については、こちら (英語) をご覧ください。

問題をデバッグするための方法は説明しましたが、最初から問題を回避できるに越したことはありません。NuGet から Microsoft.NETNative.Analyzer をアプリケーションにインストールできます。Package Manager Console でコマンド「Install-Package Microsoft.NETNative.Analyzer」を実行して、Microsoft.NETNative.Analyzer パッケージをインストールできます。開発期間中、コードに .NET ネイティブ コンパイラと互換性がない場合、このアナライザーによってエラーが表示されます。.NET の表層には互換性のない部分がわずかにありますが、大部分のアプリケーションでは問題にならないでしょう。

.NET ネイティブでアプリケーションの起動時間が向上することに関心がある場合は、ご自身でアプリケーションの起動時間を測定することも可能です。

既知の問題と回避策

Windows アプリ認定キット (WACK) を使用してアプリケーションをテストするときには、以下の点に注意してください。

  1. このコンパイル プロセスを経ていない UWP アプリで WACK を実行すると、無視できない問題が発生します。たとえば、次のようなエラーが表示されます。
    • uwphost.dll の API ExecuteAssembly はこのアプリケーションの種類ではサポートされていません。App.exe がこの API を呼び出します。
    • uwphost.dll の API DllGetActivationFactory はこのアプリケーションの種類ではサポートされていません。App.exe に、この API に転送されるエクスポートがあります。
    • ap-ms-win-core-synch-11-1-0.dll の API OpenSemaphore はこのアプリケーションの種類ではサポートされていません。System.Threading.dll がこの API を呼び出します。
    • api-ms-win-core-kernel32-legacy-11-1-0.dll の API CreateSemaphore はこのアプリケーションの種類ではサポートされていません。System.Threading.dll がこの API を呼び出します。

このようなエラーを回避するには、パッケージを適切に作成し、適切なパッケージで WACK を実行することです。パッケージ化に関するガイドラインに従うと、このようなエラーを回避できます。

  1. リフレクションを使用する .NET ネイティブ アプリケーションでは、Windows アプリ認定キット (WACK) が誤って Windows.Networking.Vpn を参照することがあります。この問題を解決するには、ソリューション エクスプローラーの rd.xml ファイルに以下のコード行を追加して再ビルドします。
    <Namespace Name=”Windows.Networking.Vpn” Dynamic=”Excluded” Serialize=”Excluded” Browse=”Excluded” Activate=”Excluded” />

まとめ

すべての Windows ユーザーが .NET ネイティブのメリットを享受できます。Windows ストアのマネージ アプリは、より高速に起動および実行するようになります。開発者は Visual Studio で慣れ親しんだ .NET 開発エクスペリエンスを利用でき、ユーザーはネイティブ コードのパフォーマンス向上というメリットを享受できます。フィードバックは、UserVoice (英語) からお寄せください。バグの報告については、Microsoft Connect からご連絡をお願いします。