May 2016

Volume 31 Number 5

ユニバーサル Windows プラットフォーム アプリ - 企業向けホステッド Web アプリケーション

Tim Kulp | May 2016

組織構造が整った企業で働く開発者は、新しいテクノロジをいつでも簡単に実装できるわけではないことを理解しています。ユニバーサル Windows プラットフォーム (UWP) アプリ プロジェクトのように新しいテクノロジを企業に導入する場合は、この種のアプリを提供する能力に長けている (または自信のある) チームがなければおそらく困難です。多くの企業は、自社のイントラネット Web アプリケーションとそれをサポートするチームに多額の投資を行っています。ホステッド Web アプリケーション (HWA) は、エンタープライズ イントラネット Web アプリケーションをほとんど手間を掛けずにビジネス向け Windows ストアに加える架け橋になります。

今回は、既存のイントラネット Web アプリケーションを Windows ストア向け UWP アプリに変換してから、ネイティブ Windows 機能を使用してこの UWP アプリを改善する過程を説明します。今回の Web アプリケーションは「Gotcha」というソーシャル表彰アプリケーションです。このアプリケーションを使って、Contoso 社の社員は、同僚の親切な行為を評価し、感謝の気持ちを表すことができます (図 1 参照)。Gotcha の目的は、チームのメンバーが互いに称賛し合うことで、堅牢かつ満足度の高いチームを作り上げることです。この Web アプリケーションには、連絡先、共有、カメラと簡単に統合できるため、Windows ストアに公開する候補として優れています。

Gotcha Web アプリケーション
図 1 Gotcha Web アプリケーション

ブリッジと企業向けホストテッド Web アプリケーション

企業の開発者にとっては、UWP ブリッジと HWA は、これまでアプリケーションに使用してきたツール、プロセス、配置システムをそのまま利用できるところに意味があります。ブリッジの考え方は、iOS や、Android、Win32、Web 向けに開発した既存のアプリケーションを UWP とクロスプラットフォーム Windows ストアに持ち込めるようにすることです。目標は、既存のコード ベースを UWP に移行できるようにし、Xbox で獲得した得点など、Windows 固有の機能を使ってそのユーザー エクスペリエンスを充実させることです。

ブリッジにより、UWP へのコードの移行が容易になります。ただし、企業の開発者が直面している課題によってはコード変換が難しくなることはあります。企業開発者の場合、使えるコード エディターの種類に制限があったり、アプリケーション内の情報の機密度によってコードの配置先に制約が設けられることもあります。企業の観点から見た UWP ブリッジの本当の価値は、アプリケーションを簡単に変換できることではなく、企業内でこれまで使われてきたソフトウェア開発ツール、手法、変更管理を変えずに、Windows ストアから UWP アプリを配信できることでしょう。

その一例として、HWA (通称「Project Westminster」) により、開発者は Web アプリケーションを UWP アプリに埋め込むことができるようになります。HWA コンテンツを使用する UWP をビルド後は、これまでと同じ方法を使って、その Web アプリケーションを管理できます。つまり、UWP アプリ内の Web アプリケーションのエクスペリエンスが自動的に更新されます。HWA ブリッジを使用すると、開発者は Web アプリケーションに注目したまま、機能検出を使って UWP 固有の機能を取り込むことができます。既存のイントラネットで機能することは、UWP ブリッジにとって優れたユース ケースですが、企業に所属しない開発者も HWA を活用して、Web アプリケーションを Windows ストアに公開することができます。Windows ストア認証プロセスに合格する Web サイトであれば、どのようなサイトでも HWA になります。

HWA の基礎については、Kiril Seksenov のブログ記事「Project Westminster の概要」(bit.ly/1PTxxW4、英語) で詳しく取り上げられています。HWA を支える考え方を理解するためにも、こちらをお読みになることをお勧めします。

Web HWA プロジェクトへの着手

Gotcha Web アプリケーションを HWA に変換するには、まず、Visual Studio で新しい JavaScript UWP アプリを作成します。作成したら、パッケージ マニフェストを開き、アプリのスタート ページを Web アプリケーションの URL に設定します (図 2 参照)。今回の場合、Gotcha Web アプリケーションは localhost:6107 から実行されます。このようにスタート ページを設定することで、Gotcha アプリはローカル コンテンツの代わりに、指定したアドレスの Web ページを表示します。

パッケージ マニフェストでのスタート ページの設定
図 2 パッケージ マニフェストでのスタート ページの設定

パッケージ マニフェストでは、最後にコンテンツの URI を設定します。コンテンツの URI は、どのページで Windows ランタイム (WinRT) ライブラリへのアクセスが可能か、さらにその URI にどのレベルのアクセス権があるかをアプリに示します。「コンテンツ URI とは、アプリが停止し、インターネットが始まる場所を定義するものだ」という説明を耳にしたことがあります。この説明の方がコンテンツ URI の使い方を想像しやすいかもしれません。既存の Gotcha Web アプリケーションでは、アプリケーションが実行することと、インターネットを使用して可能になることの区別がはっきりしています。たとえば、ユーザーは Gotcha 内から LinkedIn のようなソーシャル ネットワークと表彰を共有できます。LinkedIn Web サイトが Gotcha UWP アプリに組み込まれるわけではありません。LinkedIn はインターネット上にあります。アプリケーション内で直接使用する URI と、UWP API にアクセスする必要がある URI のみを含めます。

開発者はコンテンツ URI を使用して、未登録 URI から WinRT ライブラリにアクセスできないようにすることで、アプリのユーザーを保護できます。WinRT ライブラリに対してどのレベルのアクセス権が必要かを URI ごとに指定します。

  • すべて: Web アプリケーション (今回は Gotcha) で実行される JavaScript コードは、アプリ機能を使って定義されるすべての UWP API にアクセスできます。
  • Web のみで許可: Web アプリケーションで実行される JavaScript コードは、アプリ パッケージに含まれるカスタム WinRT コンポーネントを実行できます。ただし、すべての UWP API にアクセスできるわけではありません。
  • なし: Web アプリケーションで実行される JavaScript コードは、ローカル UWP API にはアクセスできません (既定の設定)。

コンテンツ URI を設定すると、UWP アプリ ユーザーにとってはこの URI がアプリケーション セキュリティの重要な要素になります。UWP アプリに必要な機能の URI に対して、必要最小限のアクセス許可のみを提供するようにします (図 3 参照)。本当に必要な場合を除き、ルート URI の WinRT アクセスを [すべて] に設定するのは避けます。

アプリの実行に必要最小限の特権をコンテンツ URI に設定
図 3 アプリの実行に必要最小限の特権をコンテンツ URI に設定

プロジェクトの作成過程で生まれた既存のコンテンツ (.css、.js、WinJS フォルダーなど) は削除しないようにします。こうした既存コンテンツは、ローカル コンテンツを Web HWA に追加するために使用できる優れたフレームワークを開発者に提供します。ここでは後ほど、ローカル コンテンツのフォルダーを使用して、Web HWA オフライン エクスペリエンスを補う機能をいくつか作成します。

パッケージ マニフェストを構成したら、UWP アプリを実行します。Web アプリケーションが、他の UWP アプリと同じようにアプリ ウィンドウ内に表示されるようになります (図 4 参照)。

Windows ストアに登録できる Gotcha アプリ
図 4 Windows ストアに登録できる Gotcha アプリ

ホストテッド Web アプリケーションのデバッグ

HWA のデバッグ エクスペリエンスは、純粋なネイティブ アプリとは若干異なります。UWP アプリを開き、F12 キーを押します。これにより、UWP アプリ用 F12 開発者ツールが表示されます。この F12 開発者ツールを使って、ブラウザー内で操作しているように、Web アプリケーションをデバッグ、プロファイリング、およびテストできます。F12 開発者ツールの機能はすべて HWA 開発者にとって便利なものですが、何より役立つと感じたのは、Visual Studio の外部でデバッグし、ネットワーク アクティビティをプロファイリングするコンポーネントです。これらの機能を使用して、特定のアプリの動作を詳しく調べ、アプリ内で予想外の反応を引き起こす問題 (キャッシュなど) を把握できます。

ブラウザー内で F12 を使用するのと同様、DOM を変更して、画面サイズやウィンドウ サイズに応じたさまざまな UI エクスペリエンスをテストすることもできます。これにより、レスポンシブ アプリのニーズに応じた Web アプリケーションのレイアウト変化を調査できます。たとえば、UWP アプリをスナップしてサイド バーに表示する場合、優れたエクスペリエンスにするためにアプリをリフローします。サイズが変わってもアプリがリフローされなければ、F12 開発者ツールを使ってその理由を見極め、DOM を使ってテストすることで目的のリフローを実現するために必要なことを確認します。

UWP アプリへの機能の追加

基本的な HWA を用意したところで、Web アプリケーションの機能を詳しく見ていきながら、UWP API をいくつか有効にし、ユーザー エクスペリエンスを強化してみます。イントラネット Web アプリケーションには、HWA にはない制限事項がいくつか存在することがあります。UWP API を使用すると、HWA から UWP デバイスのローカル機能 (カメラ、位置情報、その他センサーなど) の多くにアクセスできるようになります。まず、Web アプリケーションを HWA に実装するきっかけとなったユース ケースを考えてみます。Gotcha アプリでは、これまで表彰を送る相手の名前を入力していたのに代えて、ユーザーが各自の連絡先から表彰を送る相手を選択できるようにし、さらにその表彰に写真を添付できるようにしようと考えました。

最初に、Web アプリケーション上にリモート GotchaNative.js コード ファイルを作成します (GotchaNative.js スクリプト ファイルは、リモート Web アプリケーション サーバー上に置くことになります)。このコード ファイルは、ネイティブ API 名前空間を検出し、適切なコードを実行してネイティブ ユース ケースをトリガーします。次のコードを GotchaNative.js スクリプト ファイルに追加します。

var GotchaNative = (function () {
  if (typeof Windows != 'undefined') {
    // Add find contact here
    // Add capture photo here
  }});

このコードは GotchaNative オブジェクトを構築します。このオブジェクトが、UWP API のすべての機能を保持することになります。UWP API を一元化しておくと、UWP API 機能を追加するページに含めるファイルを 1 つにできます。このファイルを独立させているのは、必要な UWP API へのアクセス権をもつ URI として、この固有のファイルを含むコンテンツ URI を明示的に宣言できるようにするためです。このようにして、最小特権のセキュリティ概念を実装し、UWP API にアクセスする必要のある URI にのみアクセス許可が与えられるようにします。

このファイルを独立させるもう 1 つのメリットは、他のネイティブ プラットフォームに向けた準備にもなることです。この点については後ほど説明しますが、今のところは、Gotcha Web アプリケーションに組み込むすべてのネイティブ機能のホームになるのがこのファイルだと考えてください。

既存機能の拡張

これで GotchaNative オブジェクトを作成できたので、HWA を UWP API に接続する具体的な機能を追加します。最初のユース ケースでは、Gotcha Web アプリケーションは、ユーザーが表彰する相手を入力できるようにしていました。UWP では、ユーザーが相手の名前を入力するよりも簡単に選択できるように、連絡先を保存している People アプリを利用します。GotchaNative.js コード内の「Add find contact here」というコメントを以下のコードに置き換えます。

this.FindContact = function () {
  var picker = new Windows.ApplicationModel.Contacts.ContactPicker();
  picker.desiredFieldsWithContactFieldType.append(
    Windows.ApplicationModel.Contacts.ContactFieldType.email);
  return picker.pickContactAsync();
}

このコードでは、連絡先の一覧から連絡先を選択するため ContactPicker API に基本的な接続を行っています。Web HWA に組み込める UWP API の一覧は、rjs.azureWebsites.net (英語) で確認できます。この Web サイトでは、よく使用される API もいくつか一覧されています。Web HWA プロジェクトの構築に役立つコピーや貼り付けに対応するコードもあります。

相手を追加する機能は、Gotcha Web サイト用ビューモデル Person にあります。図 5 のコードをビューモデル Person に追加します。

図 5 ビューモデル Person に追加するコード

if (Windows != undefined) {
  var nativeGotcha = new NativeGotcha();
  nativeGotcha.FindContact().done(function (contact) {
    if (contact !== null) {
      $("#txtWho").val(contact.displayName);
    } else {
      // Write out no contact selected
    }
  });
}
else {
  $('#add-person').on('shown.bs.modal', function () {
    $("#txtWho").focus();
}

スクリプトを HWA として実行するため、Windows オブジェクトを定義している場合、図 5 のコードでは FindContact メソッドを使用しています。Windows オブジェクトを定義していない場合、Web アプリケーションは引き続き既存の Bootstrap モーダル ウィンドウを使用して、表彰する相手に関する情報を収集します。このコードでは、Web アプリケーション 1 つのアプローチを使って表彰する相手を入力できるようにしながら、UWP アプリでは、ユーザーが、細かく調整された別のアプローチを利用できるようになります。

新しい機能の追加

UWP API を有効にすることで、Web アプリケーションには通常存在しない新しい機能を実現できる場合があります。Gotcha HWA では、ユーザーが写真を撮影し、表彰としてその写真を他の Gotcha ユーザーに送れるようにしようと考えました。この機能は Gotcha アプリケーションにはこれまでなかったもので、Web アプリケーションには存在しない機能です。HWA を構築するときは、UWP API を使ってアプリの可能性を広げることを検討します。

この新しい機能を実装するには、まず GotchaNative.js コード ファイル内の「Add capture photo」というコメントを以下のコードに置き換えます。

this.CapturePicture = function () {
  var captureUI = new Windows.Media.Capture.CameraCaptureUI();
  captureUI.photoSettings.format =
    Windows.Media.Capture.CameraCaptureUIPhotoFormat.png;
  return captureUI.captureFileAsync(
    Windows.Media.Capture.CameraCaptureUIMode.photo);
}

上記のコードでは、capture UI を開き、ユーザーが写真を撮影できるようにして、撮った写真を呼び出し元に返します。Windows オブジェクトを定義している場合、Web アプリケーションでこの新機能を有効にする必要があります。ビューモデル Person と同様に機能検出を使うため、図 6 のコードをビューモデル Home に追加します。このビューモデルには表彰を追加するためのコードがあります。

図 6 ビューモデル Home に追加する機能検出コード

$('#give-modal').on('shown.bs.modal', function () {
  if (typeof Windows != 'undefined') {
    var gotchaNative = new NativeGotcha();
    $("#btnCamera").click(function () {
      gotchaNative.CapturePicture().then(function (capturedItem) {
        // Do something with capturedItem;
      });
    }).show();
  }
  else {
    $("#btnCamera").hide();
  }
})

図 6 のコードでは、Windows オブジェクトを定義していない場合は btnCamera を非表示にしています。Windows オブジェクトを定義している場合は、CapturePicture 関数をトリガーするように click イベントを構成します。説明を簡単にするため、写真を使って行う作業はコメントの形で残してあります。カメラが有効になっていても、この HWA は UWP アプリなので、このアプリに対して Web カメラ機能を有効にする必要があります。これは、パッケージ マニフェストで行います。

企業の Web アプリケーションを HWA に変換して、Windows ストアの UWP API を利用できるようにします。既存の Web アプリケーションを使用すれば、Windows ストアから配布する UWP アプリを簡単に作成できます。ただし、HWA はインターネットに接続することが前提です。そこで、インターネットにアクセスしなくても機能するアプリにする方法を見ていきます。

オフラインでの接続

UWP アプリはローカル ファイルを用意することで、オフライン (ローカル) でのエクスペリエンスを提供できます。ローカル コンテンツを使用すれば、一部の UWP API 呼び出しを HWA から切り離すことができます。ここまでに実行した機能検出と同様、ローカル コンテンツにリンクするには、リンクをアクティブにします。Gotcha の場合は、ローカル マッピング コントロールを使用するマッピング機能を追加します。

HWA では、前述のビューモデル Home で使用したのと同じ機能検出を使用します。正しい URI スキームを使用することで、HWA は Web コンテンツとローカル コンテンツを切り替えられるようになります。ホーム画面に以下のリンクを追加します。

<a href="ms-appx:///default.html" id="lnkMap">
  <span class="glyphicon glyphicon-map-marker">&nbsp;</span> Show Map
</a>

このリンクは ms-appx:/// スキームに接続します。このスキームによって、アプリケーション パッケージ内のローカル コンテンツにアプリケーションから接続できるようになります。ms-appx スキーム内で動作しているアプリは必要な UWP API に接続できます。これはコンテンツ URI を使用して、API にアクセスするページにどのレベルのアクセス権があるかを宣言するのに似ています。ms-appx を使用することは URI を "すべて" とマークすることに似ています。今回の場合、defalt.html ページに UWP API へのアクセス権があります。HWA 内にリンクが表示されたら、ユーザーはそのリンクをクリックすることで、アプリ パッケージ内部で機能するようになります。

企業開発者がこの機能を使用することで、UWP 固有のユース ケースと、Web アプリケーションに接続する必要のないユース ケースを分離します。パッケージ コンテンツに接続しても、UWP API へのアクセス権が Web アプリケーションに提供されなくなり、アクセスをすべてパッケージ内に留めることができます。

複数のストアについて

企業によっては、私有デバイスの業務使用 (Bring Your Own Device) を許可する環境が存在する場合があります。つまり、既に iOS や Android デバイスを既存アプリのターゲットにしている場合があります。Android アプリと iOS アプリには HWA と似た概念があり、これを WebView コントロールと呼びます。WebView により、開発者はアプリ内のウィンドウを既存の Web アプリケーションに提供でき、その Web アプリケーションをネイティブ アプリの一部であるかのように操作できます。HWA は他と調和するように構築できるため、提供するプラットフォームに合わせて既存の Web アプリケーションの機能を調整できます。ここからは、GotchaNative.js を更新して Android のサポートを追加し、HWA コードと、他のプラットフォームをターゲットにする JavaScript をサイドバイサイドでアクティブにするしくみを説明します。

前半で GotchaNative.js をセットアップしました。このファイルには、アプリのネイティブ コードすべてを保持する目的があります。これらのネイティブ メソッドの出力はビューモデルで処理します。任意のプラットフォームの API を使用する手順は、HWA に似ています。つまり、まず、ネイティブ API を利用できるかどうかを判断してから、適切な API を呼び出す必要があります。GotchaNative.js を更新するには、どのネイティブ プラットフォーム (存在する場合) が認識されているかを示すプロパティを追加します。以下の例では、ローカル スクリプトの名前空間として "Android" を宣言する WebView が Android アプリで使用されることを前提としています。

this.Platform = function () {
  if (Windows != 'undefined')
    return "Windows";
  else if (Android != 'undefined')
    return "Android";
  else
    return "Web";
}

この関数は、操作対象のプラットフォームをコードから判断できるようにします。そうすれば、そのプラットフォームに対応するように、コードを調整できます。ここからの例では、GotchaNative.js 内の各メソッドでプラットフォームをチェックすることで処理方法を判断しています (図 7 参照)。

図 7 プラットフォームをチェックする GotchaNative.js メソッド

this.CapturePicture = function () {
  switch (this.Platform()) {
    case "Windows":
      var captureUI = new Windows.Media.Capture.CameraCaptureUI();
      captureUI.photoSettings.format =
        Windows.Media.Capture.CameraCaptureUIPhotoFormat.png;
      return captureUI.captureFileAsync(
        Windows.Media.Capture.CameraCaptureUIMode.photo);
      break;
    case "Android":
      Android.CaptureFile(); // Calls Android code in Native app
      break;
    default:
      return null;
      break;
}

ここでビューモデルのコードを更新して、プラットフォームを検出し、GotchaNative メソッドの出力の処理方法を把握します。以下のコードは、ビューモデル Home のカメラ ボタン イベントに対する更新です。

$("#btnCamera").click(function () {
  switch (gotchaNative.Platform()) {
    case "Windows":
      gotchaNative.CapturePicture().then(function (capturedItem) {
        // Do something with capturedItem;
      });
      break;
    case "Android":
      // Handle Android output
      break;
  }
}).show();

これで、アプリは複数のプラットフォームをサポートしながら、コードの 1 つの場所ですべてのプラットフォームの機能を改良できるようになります。将来、新たに人気の OS が登場したとしても、開発チームはその新しいプラットフォーム向けにコードを調整することができます。

まとめ

企業開発者はその取り組みの中で数え切れないほどの課題に直面します。標準化されたプロセスやツールは、UWP アプリのような新しいテクノロジの実装を妨げる障害と見なされることがあります。UWP ブリッジを使用すれば、企業開発者は既存のイントラネット Web アプリケーションや社外向け Web アプリケーションを Windows ストア (一般向けまたはビジネス向け Windows ストア) に持ち込むことができます。HWA 用ブリッジは、Web アプリケーションをクロスプラットフォーム UWP アプリに変換でき、UWP API を活用してユーザー エクスペリエンスを充実させることができます。

今回は、既存の Web アプリケーションを HWA に変換すると同時に、カメラや連絡先へのアクセスなど、UWP アプリ固有の機能を追加する方法を取り上げました。ms-appx スキームを使用して、HWA とアプリ パッケージ内のローカル コンテンツを切り替える方法や、多様なプラットフォームを念頭に置いて HWA を構築する方法も説明しました。これにより、企業は広がり続けるモバイル デバイスの世界に遅れることはなくなります。ここで取り上げた手法を用いることで、HWA を使って Web アプリケーションに対する既存の投資を活用でき、Windows ストア エコシステムへの企業の参加が後押しされます。


Tim Kulp は、メリーランド州ボルチモア在住の上級テクニカル アーキテクトで、Web、モバイル、および UWP の開発者、著者、絵描き、父親を兼務し、「熱狂的な科学者を生み出したい」と願っています。彼には Twitter (@seccode、英語) または LinkedIn (linkedin.com/in/timkulp、英語) から連絡できます。

この記事のレビューに協力してくれたマイクロソフト技術スタッフの John David Dalton と Kiril Seksenov に心より感謝いたします。