次の方法で共有


Cutting Edge

ASP.NET MVC 4 でモバイル向けに最適化したビューを作成する (第 2 部): WURFL を使用する

Dino Esposito

Dino Esposito10 年前のブラウザー戦争の古い記憶は、今でも開発者に恐れを抱かせます。jQuery が幅広く普及した理由の 1 つは、どのブラウザーにもドキュメント オブジェクト モデル (DOM) と JavaScript が実装されたことで、ブラウザー間の差異を吸収できることにありました。現在の開発者はおそらく特定のブラウザーの能力を考えなくても機能に集中できます。本当でしょうか。このことは、デスクトップ ブラウザーには当てはまっても、モバイル ブラウザーにはあまり当てはまりません。

モバイル ブラウザーは、10 年前のデスクトップ ブラウザーの状況に比べるとはるかに細分化された状態になっています。以前は考慮する必要のあるデスクトップ ブラウザーの種類は数十程度でしたが、モバイル ブラウザーの種類は数千にも上ります。デバイスのフォーム ファクターは、スマートフォンやミニタブレットのように小型化する方向と、スマート TV のように大型化する方向へと大きく分化していきます。現在も、そして将来も成功を収めるために重要なのは、どのクラスのデバイスを使用しているユーザーにも適切なエクスペリエンスを提供することです。そのためには、まずデバイスを検出し、その能力を把握する必要があります。

古き良きブラウザーの能力をまとめたデータベース

バージョン 1.0 以来、ASP.NET はブラウザーの能力をまとめたデータベースを提供しています。要求元ブラウザーの能力を HttpRequest オブジェクトによって公開される Browser プロパティに照会できます。ブラウザーの能力をまとめるインフラストラクチャのしくみは、非常に簡単かつ効果的です。HttpRequest オブジェクトを構築するときに、ASP.NET ランタイムはユーザー エージェント文字列を取得し、ASP.NET ブラウザー データベースに照会を行います。ユーザー エージェント文字列をキーとして使用して、既知の能力の一覧を取得し、値を HttpBrowserCapabilities オブジェクトに格納して、そこに開発者が Request.Browser を通じてアクセスします。知る限りでは、この機能は ASP.NET 固有で、他の Web 開発プラットフォームには同様の機能がありません。

ブラウザーの能力をまとめるという考え方を見ていくと、このフレームワークには問題点があることが明らかになります。つまり、この考え方が効果を発揮するには、新しいデバイスやブラウザーが市場に出るたびに、ブラウザーの能力をまとめたデータベースを定期的に更新しなければなりません。

本来、マイクロソフトは、このブラウザーの能力をまとめるフレームワークをいくつかのデスクトップ ブラウザーを区別するために設計しましたが、モバイル デバイスが登場したことにより、この問題の重要性がまったく変わってしまいました。しばらくの間、マイクロソフトは個々のモバイル デバイスとブラウザーの能力の定義に関する充実したデータベースの作成を目指し、Mobile Device Browser File (MDBF) プロジェクト (mdbf.codeplex.com、英語) をサポートしていました。考え方は、ASP.NET から受け取る標準 .browser ファイルを単純に MDBF に置き換え、Request.Browser を使用してブラウザーとモバイル デバイスの詳細な情報にアクセスしようというものです。しかし、このプロジェクトは数年前に打ち切られました。それでも、基になる考え方は非常に有効で、カスタマイズして高度に最適化したコンテンツをいくつかのクラスのデバイスに提供するおそらく最も効果的な方法なので、今回は ASP.NET MVC 4 でこれを実現する方法を紹介します。今回の例では、wurfl.sourceforge.net (英語) で参照できる Wireless Universal Resource FiLe (WURFL) からデバイスに関するすべての情報を取得します。数ある中でも、WURFL は、Google や Facebook など多くの大企業で使用されているデバイス説明リポジトリ (DDR: Device Description Repository) です。WURFL と DDR の詳細については、「モバイル サイト開発: マークアップ」(msdn.microsoft.com/magazine/jj133814) から始まるモバイル サイト開発に関する連載の以前のコラムを参照してください。

ASP.NET MVC 4 のモバイル面

ASP.NET MVC 4 では、図 1 のコードを global.asax から呼び出して、同一の Razor ビューで最大 3 つの異なる表示を行えるよう準備します。

図 1 ASP.NET MVC 4 が同一の Razor ビューで最大 3 つの表示モードをサポートするよう指示する

public class DisplayConfig
{
  public static void RegisterDisplayModes(
    IList<IDisplayMode> displayModes)
  {
    var modeSmartphone = new DefaultDisplayMode("smart")
    {
      ContextCondition = (c => c.Request.IsSmartphone())
   };
   var modeTablet = new DefaultDisplayMode("tablet")
   {
     ContextCondition = (c => c.Request.IsTablet())
   };
   var modeDesktop = new DefaultDisplayMode("")
   {
     ContextCondition = (c => c.Request.IsDesktop())
   };
   displayModes.Clear();
   displayModes.Add(modeSmartphone);
   displayModes.Add(modeTablet);
   displayModes.Add(modeDesktop);
  }
}

RegisterDisplayModes は、ASP.NET MVC 4 ランタイムがビューごとに 3 種類の異なる表示モードを検討するよう指示します。つまり、コントローラーがビューを呼び出すたびに、ビューの実際の名前 ("インデックス") が表示モード プロバイダーによって調査され、スマートフォンまたはタブレット用に定義されたコンテキスト条件が確認されたら、名前を index.smart または index.tablet に変更します。プロバイダーで表示モード オブジェクトが挿入される順番が重要です。検索は、実際のところ、最初に適合したコンテキスト条件で停止します。たとえば、HTTP 要求が次のコードのようになったとします。

public ActionResult Index(){  return View();}

ASP.NET MVC では、ビュー名を解決しながら、表示モードのコレクションを順を追って確認します。最初に確認するのは、スマートフォン表示モードです。スマートフォンのコンテキスト条件により、IsSmartphone の実装に応じて true または false が返されます。true の場合、サフィックスに "smart" が付いたビューが選択されます (存在する場合)。false の場合、次に使用可能な表示モードを続けて検索します。

どの要求がどの表示モードに対応するかを決める条件を定義するのも、表示モードの数を定義するのも開発者です。

要求と表示モードを対応付けるには、デバイス検出が必要です。ただし、考えられるデバイスごとに 1 つのビューを用意する必要はなく、アプリケーションでサポート予定のデバイスのクラスごとに 1 つのビューを用意すれば問題ありません。

デバイスの検出をスマートにする

デバイスの検出とは、結局のところ、ユーザー エージェント文字列を識別することです。ユーザー エージェント文字列は厳密に定められた体系ではありません。そのため、理解しやすい形にして能力の一覧に簡単に対応付けられるようにするには、解析と正規化を何回も行う必要があります。新しいブラウザーのバージョンやデバイスのリリース、OEM による OS のカスタマイズが行われるたびに調査を行う必要があるため、このようなデータベースのメンテナンスにはコストがかかります。さらに、識別した一意のデバイスごとに能力を明らかにして、データベースに効率的に格納する必要があります。

数社の企業がこの分野で活動し、非常に安価なクラウドベースのソリューションを含めたさまざまなモデルに応じた製品を販売しています。デバイスの検出で最も一般的なフレームワークが前述の WURFL です。これは、さまざまな言語で使用可能なクロスプラットフォーム ライブラリで、Affero General Public License (AGPL) に基づくオープン ソースでもあります。ASP.NET MVC 4 の開発者は、NuGet パッケージとして WURFL を利用することもできます。Microsoft .NET Framework を使用する環境では、51Degrees データベース (51degrees.mobi、英語) という選択肢もあります。ここからは、デバイス検出フレームワークを使用して、ASP.NET MVC 4 アプリケーションで表示モードをルーティングする方法について説明します。

WURFL を表示モードに追加する

図 1 のコードは、基本的に、次の ContextCondition デリゲートをまとめたものです。

Boolean ContextCondition(HttpContextBase)

シグネチャは見てのとおりです。HTTP コンテキストが渡され、ブール値の答えを受け取ります。デリゲートのロジックでは、HTTP コンテキストの情報を使用して、要求に対し、目的のビューを表示モードで提供できるかどうかを判断します。例として、前回のコラム「ASP.NET MVC 4 でモバイル向けに最適化したビューを作成する」(msdn.microsoft.com/magazine/dn296507) の続きから始めます。図 1 で使用している IsTablet メソッドは、HttpRequestBase クラスに追加された拡張メソッドです。コードは次のとおりです。

public static class HttpRequestBaseExtensions
{
  public static Boolean IsTablet(this HttpRequestBase request)
  {
    var ua = userAgent.ToLower();
    return ua.Contains("ipad") || ua.Contains("gt-");
  }
}

モバイル デバイスが急速に進化するため、タブレットとスマートフォンはそれぞれどのようなものかという固定的な定義を明らかにし、維持するのが困難になっています。タブレットやスマートフォンであることを、Flash ビデオ (.flv) ストリーミングやインライン イメージのサポートがあるかどうかなどといった物理特性と考えることはできません。デバイスのクラスは、定義がすべて開発チームにより決定された仮想能力を上回るものです。仮想能力は通常複数の物理能力の論理的な組み合わせとして実装されます。

WURFL を ASP.NET MVC 4 コードに追加するには、NuGet を起動して、公式の WURFL API を取得するだけです。パッケージにより、App_Data フォルダーに WURFL データベース (zip ファイル) がインストールされます。このデータベースは、デバイス情報の比較的最近のスナップショットです。毎週更新するためには、ScientiaMobile (scientiamobile.com、英語) から商用ライセンスを購入する必要があります。

WURFL のインストールが終了したら、Application_Start に次の行を追加します。

WURFLManagerBuilder.Build(new ApplicationConfigurer());

これで、想定されるアクセスに迅速に対応するためのデータベースがメモリに読み込まれ、すべてのデータがキャッシュされます。WURFL クエリを実行するには、HTML ビューに対する全要求に対して次のコードを毎回実行する必要があります。

var userAgent = ...; // Typically read from Request object
var device = WURFLManagerBuilder.Instance.GetDeviceForRequest(userAgent);

このコードも、見てのとおりです。WURFL フレームワークはユーザー エージェントを取得し、デバイスに関して判明しているすべての情報をわずか数ミリ秒で返します。情報は、名前/値のコレクションの形式で表現されます。名前と返される値はどちらも文字列です。文字列を厳密に型指定されたデータ (整数型、ブール型など) に変換するのは開発者の役割です。WURFL では、デバイスがいくつかのカテゴリにカタログ化されており、各デバイスにつき 500 以上の能力が示されています。もちろん、それらすべてが必要になることはないでしょう。現実的な数字としてはこの 1/10 です。この数字は、今はなき MDBF プロジェクトでサポートされていた能力の数と一致します。いずれにせよ、この数字は CSS3 メディア クエリで確認できる能力数よりもはるかに多くなります。メディア クエリには合計 5 つのプロパティがあり、よく使われるのはそのうちの 1 つか 2 つ (width と orientation) です。WURFL を使用してタブレットかどうかを確実にチェックする方法を次に示します。

public static class HttpRequestBaseExtensions
{
  public static Boolean IsTablet(this HttpRequestBase request)
  {
    var device =
       WURFLManagerBuilder.Instance.GetDeviceForRequest(userAgent);
   return device.IsTablet();
  }
}

IsTablet は、WURFL IDevice 型の拡張メソッドで、型指定が厳密ではないという WURFL の性質に対処するためだけに作成しました。

public static Boolean IsTablet(this IDevice device){
  return device.GetCapability("is_tablet").ToBool();
}

ToBool も拡張メソッドで、Boolean.TryParse 呼び出しをラッピングしているだけです。

コードをわかりやすく、洗練された状態に保つのに拡張メソッドが便利であることは、図 2 のスマートフォンを検出するサンプル コードを見ると明らかです。おそらく、スマートフォンとは何か関して、万人が同意する共通の定義は存在しません。複数の WURFL プロパティを組み合わせることで、図 2 のように独自のスマートフォンの定義を作成できます。

図 2 スマートフォンの仮想能力を定義する

public static class HttpRequestBaseExtensions
{
  public static Boolean IsSmartphone(this HttpRequestBase request)
  {
    var device =
      WURFLManagerBuilder.Instance.GetDeviceForRequest(userAgent);
    return device.IsWireless() && !device.IsTablet() &&
      device.IsTouch() &&
      device.Width() > 320 &&
      (device.HasOs("android", new Version(2, 2)) ||
      device.HasOs("iphone os", new Version(3, 2)) ||
      device.HasOs("windows phone os", new Version(7, 1)) ||
      device.HasOs("rim os", new Version(6, 0)));
  }
}

図 2 のコードでは、タブレットではなく、タッチ操作対応で、320 ピクセル以上の幅があり、指定された OS のどれかを実行するワイヤレス デバイスとしてスマートフォンを定義しています。device 変数で使用されるすべてのメソッドは、WURFL ネイティブの機能の上位に作成した拡張メソッドです。

サーバー側の検出とクライアント側のレスポンシブ デザイン

一部業界でクライアント側での機能検出が注目されるのは、Web サイトで高度な HTML5 と CSS3 機能を使用するという目的からきています。しかし、これは、モバイル対応サイトの作成にはあまり関係ありません。クライアント側での機能検出は、ブラウザーから検出可能で、メディア クエリで取得できたり、プログラムによってテストできるせいぜい 5 つのプロパティに限られます。Android デバイスと iPhone とを区別するには、ユーザー エージェント識別が必要です。たとえば、Android 2.2 を実行していても、実際のデバイス能力の詳細についてはわからないことは言うまでもありません。

デバイス (小型および大型) に対してアドホックなマークアップを提供する必要がある場合は、サーバー側でデバイスと機能の検出を行うのが唯一の方法です。これは、WURFL を使用すると迅速かつ簡単に実現できます。

サーバー側での検出とクライアント側のレスポンシブ デザインのどちらか一方だけを選択する必要はありません。サーバー側の検出は、デバイスと関連する表示モードを識別するためだけのものです。提供するマークアップには、メディア クエリ、リキッド レイアウトなど、表示の向上に役立つ要素を簡単に含めることができます。この手法は、レスポンシブ デザイン + サーバー側コンポーネント (RESS: Responsive Design + Server-Side Components) と呼ばれます。サーバー側での検出は、カスタマイズしたビューの構築プロセスに抽象化のレベルを 1 つ追加するだけです。

Dino Esposito は、『Architecting Mobile Solutions for the Enterprise』(Microsoft Press、2012 年) および近日 Microsoft Press から刊行予定の『Programming ASP.NET MVC 5』の著者です。JetBrains の .NET および Android プラットフォームのテクニカル エバンジェリストでもあります。世界各国で開催される業界のイベントで頻繁に講演しており、software2cents.wordpress.com (英語) や Twitter (Twitter.com/despos、英語) でソフトウェアに関するビジョンを紹介しています。

この記事のレビューに協力してくれた技術スタッフの Mani Subramanian (マイクロソフト) に心より感謝いたします。