ASP.NET MVCで作る携帯サイト(2)
ソースに関して最初に言っておくと、絵文字変換について、.NETでのやりかたの検証用に作ってみたものなので、実用性の検証はしていません。
中身についても、割とエエエェェェ(´д`)ェェェエエエな事をしています。
まあ、そこは了承してもらうということで、絵文字変換ライブラリSmart.Web.Mobileのソース&サンプルとその解説です(・∀・)
ソースとサンプル
CodePlexにあげておきました(・∀・)
http://usaxusa.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=37417
っで、まずは使い方と言うことで、サンプルの解説をしてみたいと思います。
ブラウザ定義ファイル
ASP.NETにはブラウザ定義ファイルの仕組みがありますが、Smart.Web.Mobileではそれは使用しません(・ω・)
っというかむしろ邪魔なので、App_Browsersフォルダ下に下記のような内容の定義ファイルを作って、標準設定を無効化しています。
<browser refID="Docomo"> <capabilities> <capability name="preferredRequestEncoding" value="" /> <capability name="preferredResponseEncoding" value="" /> </capabilities> </browser>
System.Web.UI.Pageクラスは、preferredRequestEncoding、preferredResponseEncodingが設定されている場合にその内容をContentEncodingに設定してくれちゃいます(´д`;)
Smart.Web.Mobileではキャリア毎のエンコードは自前で行うため、この処理が動かないように設定を上書きして無効化しています。
なお、基本方針としてWeb.configのglobalization等の設定は行わず、エンコードの処理はSmart.Web.Mobileに任せることになります。
設定ファイル
Smart.Web.Mobileの設定ファイルとして、App_Data/Mobile下に4つのファイルがあります。
mobile.xmlは全体の定義で、キャリアの判定ルール等が記述してあります。
同様の仕組みはブラウザ定義ファイルにもありますが、そこには依存しない方針なので自前でやっています。(ただし割とおおざっぱ(´д`;))
っで、その他のdocomo.xml、au.xml、softbank.xmlはキャリア毎の絵文字の定義と、キャリア間の変換ルールの定義になります。
中身はこんな風になっていて(・ω・)
<?xml version="1.0" encoding="utf-8" ?> <carrier name="docomo"> <pictgrams> <pictgram no="1" sjis="F89F" unicode="E63E" name="晴れ" /> <pictgram no="2" sjis="F8A0" unicode="E63F" name="曇り" /> <pictgram no="3" sjis="F8A1" unicode="E640" name="雨" /> <pictgram no="4" sjis="F8A2" unicode="E641" name="雪" /> <pictgram no="5" sjis="F8A3" unicode="E642" name="雷" /> <pictgram no="6" sjis="F8A4" unicode="E643" name="台風" /> <pictgram no="7" sjis="F8A5" unicode="E644" name="霧" /> ... <pictgram no="1001" sjis="F9B1" unicode="E70C" name="iアプリ" /> <pictgram no="1002" sjis="F9B2" unicode="E70D" name="iアプリ(枠付き)" /> ... </pictgrams> <converts> <convert no="1" au="44" softbank="74" /> <convert no="2" au="107" softbank="73" /> <convert no="3" au="95" softbank="75" /> <convert no="4" au="191" softbank="72" /> <convert no="5" au="16" softbank="161" /> <convert no="6" au="190" softbank="467" /> <convert no="7" au="305" softbank="[霧]" /> ... <convert no="1001" au="[iアプリ]" softbank="[iアプリ]" /> <convert no="1002" au="[iアプリ]" softbank="[iアプリ]" /> ... </converts> </carrier>
pictgrams下が絵文字の定義で、No、Shift-JIS、Unicodeの対応表になっています。
converts下は絵文字の変換ルールで、他のキャリアでどのように表示するかを定義しています。
変換ルールは、値が数値の場合はそのキャリアでの絵文字Noで、数値以外の場合は文字列として出力する内容になります。
また、タグも許可しているので、ここを弄ればタグで装飾した内容に変換することも可能です。
サンプルの設定では、PC用(other)についてはimgタグに変換するようにしてあります。*1
初期化/入力設定
Smart.Web.Mobileを使用するための初期化処理をHttpApplicationで行います。
public class MvcApplication : System.Web.HttpApplication { public MvcApplication() { this.PreRequestHandlerExecute += OnPreRequestHandlerExecute; } protected void Application_Start() { RegisterRoutes( RouteTable.Routes ); // 初期化 MobileSettings.Default.Init( Server.MapPath( "App_Data\\Mobile\\mobile.xml" ) ); } private void OnPreRequestHandlerExecute(object sender, System.EventArgs e) { if( Response.ContentType == "text/html" ) { // コンテキスト初期化 WebMobileContext.Current.Initialize( Request.UserAgent, MobileSettings.Default ); // エンコーディング Request.ContentEncoding = SitePolicy.GetEncodingForCurrentTarget(); } } }
初期化処理として、MobileSettingsに設定ファイルを読み込んでおきます。
また、リクエストに対してはUser-Agentによるキャリアの判別と、エンコーディングの設定を行います。
なお、キャリア毎にどの文字コードを使うか、絵文字の出力方法をどうするか等の設定については、アプリケーション固有のSitePolicyクラスにまとめていますが、その説明については後述します(・ω・)
出力設定
レスポンスに対する設定を行うため、下記のような属性を作成しています。
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false )] public class MobileResponseAttribute : FilterAttribute, IActionFilter, IResultFilter { public void OnActionExecuting(ActionExecutingContext filterContext) { // 出力設定 SitePolicy.SetResponseForCurrentTarget( filterContext.HttpContext.Response ); } public void OnActionExecuted(ActionExecutedContext filterContext) {} public void OnResultExecuting(ResultExecutingContext filterContext) {} public void OnResultExecuted(ResultExecutedContext filterContext) { if( filterContext.HttpContext.Response.ContentType == "text/html" ) { SitePolicy.SetContentTypeForCurrentTarget( filterContext.HttpContext.Response ); } } }
っで、Controllerクラスに対して属性を付与することにより、そのControllerのアクションからの出力をSmart.Web.Mobileで処理するようにしています。
[MobileResponse] public class MobileController : Controller { ... }
詳細はSitePolicyクラスの説明で書きますが、SitePolicy.SetResponseForCurrentTarget()で行っているのはHttpRespinse.ContentEncoding、HttpRespinse.Filterの設定になります。
また、SitePolicy.SetContentTypeForCurrentTargetで行っているのはHttpRespinse.ContentTypeの設定になります。
SitePolicy
サイト固有の携帯対応の設定については、SitePolicyクラスに処理をまとめています。
SitePolicyではキャリア毎の文字コードの設定、絵文字の出力方法の設定、Content-Typeの設定を行っていますが、まずは文字コードの設定について、サンプルでは下記のようにしています。
public static Encoding GetEncodingForCurrentTarget() { Carrier carrier = WebMobileContext.Current.Carrier; Encoding encoding = Encoding.UTF8; if( WebMobileContext.Current.IsMobile ) { string encode = ( ( ( carrier == Carrier.DoCoMo ) || ( carrier == Carrier.Au ) ) ? "Shift_JIS" : "UTF-8" ); encoding = WebMobileContext.Current.CarrierSettings.GetMobileEncoding( encode, PictgramTreat.Convert ); } return encoding; }
DoCoMoとauはSjift_JISベース、SoftbankとPCはUTF-8ベースの設定になります。
なお、携帯についてはEncoding.GetEncoding()で取得したEncodingではなく、Smart.Web.Mobileで用意したMobileEncodingを返すようにしています。
MobileEncodingは、絵文字の削除機能と、キャリア規定のマッピングによるShift_JIS-Unicode変換機能を持ったEncodingの実装です。
CarrierSettings.GetMobileEncoding()はそのファクトリです。
次に、出力設定は下記のようになっています。
public static void SetResponseForCurrentTarget(HttpResponseBase response) { Carrier carrier = WebMobileContext.Current.Carrier; // レンダリング IPictgramRender render = null; if( carrier == Carrier.DoCoMo ) { render = new DocomoMixedRender(); } if( carrier == Carrier.Au ) { render = new SjisNumberRender(); } if( carrier == Carrier.Softbank ) { render = new UnicodeNumberRender(); } // エンコーディング Encoding encoding = GetEncodingForCurrentTarget(); // 出力設定 response.ContentEncoding = new MobileOutputEncoding( Encoding.Unicode, encoding ); response.Filter = new MobileOutputStream( response.Filter, Encoding.Unicode, encoding, WebMobileContext.Current.CarrierSettings ) { Trim = true, Effect = (x) => KanaConverter.Convert( x, KanaOption.Narrow ), PictgramRender = render, }; }
IPictgramRenderは絵文字の出力方法の指定で、この例ではキャリア毎に設定を変える内容になっています。
例えば、Softbank用にはUnicodeNumberRenderクラスを設定していますが、これはUnicodeの実体参照を使った出力方法になります。
また、絵文字のキャリア間変換及びその他の設定として、MobileOutputEncodingクラスとMobileOutputStreamクラスをHttpResponseに設定しています。
MobileOutputEncodingとMobileOutputStreamはニコイチで動作する仕掛けになっていますが、その辺の話はソースの解説の時に行います。
なお、MobileOutputStreamにはオプションとして、空行削除のTrimプロパティ、かな文字の半角変換等を行うためのEffectプロパティ、IPictgramRenderの指定を行うPictgramRenderプロパティが存在します。
後はContent-Typeの設定ですが、サンプルではそのキャリアに対しても「application/xhtml+xml」を設定するようにしています。
public static void SetContentTypeForCurrentTarget(HttpResponseBase response) { Carrier carrier = WebMobileContext.Current.Carrier; if( carrier == Carrier.DoCoMo ) { response.ContentType = "application/xhtml+xml"; } if( carrier == Carrier.Au ) { response.ContentType = "application/xhtml+xml"; } if( carrier == Carrier.Softbank ) { response.ContentType = "application/xhtml+xml"; } }
この辺は使用する文字コードとキャリアにあわせて設定します。
なお、Content-Typeのcharserの設定はASP.NETがやってくれるので、自分では記述していません(・ω・)
ビュー
まず、マスターページMobile.masterはこんな風にしています。
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %> <% Carrier carrier = WebMobileContext.Current.Carrier; %> <% if( carrier == Carrier.DoCoMo ) { %> <%= Html.Xml() %> <!DOCTYPE html PUBLIC "-//i-mode group (ja)//DTD XHTML i-XHTML(Locale/Ver.=ja/2.0) 1.0//EN" "i-xhtml_4ja_10.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <% } else if( carrier == Carrier.Au ) { %> <%= Html.Xml() %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <% } else if( carrier == Carrier.Softbank ) { %> <%= Html.Xml() %> <!DOCTYPE html PUBLIC "-//WAPFORUM//DTD WML 2.0//EN" "http://www.wapforum.org/wml20.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wml="http://www.wapforum.org/2001/wml"> <% } else { %> <%= Html.Xml() %> <!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd" > <html xmlns="http://www.w3.org/1999/xhtml"> <% } %> <head runat="server"> <title> <asp:ContentPlaceHolder ID="TitleContent" runat="server"> </asp:ContentPlaceHolder> </title> <%= Html.Charset() %> </head> ...
ベタな書き方ですが、キャリア毎にDOCTYPE宣言を変えてみたりしています。
なお、Html.Xml()、Html.Charset()は文字コードを考慮した出力用のヘルパーですが、詳細はサンプルの中を見てくださいな。
また、ビューIndex.aspxで以下のように絵文字の出力をしています。
<%= Html.Pictgram( Carrier.DoCoMo, 125 ) %>:DoCoMo 125<br/> <%= Html.Pictgram( Carrier.Au, 181 ) %>:au 181<br/> <%= Html.Pictgram( Carrier.Softbank, 230 ) %>:Softbank 230<br/>
Pictgram()メソッドもヘルパーとして用意していますが、中身はSmart.Web.Mobileの機能を使って、Noに対するUnicodeの1文字を出力するだけのものです。
その内容が、MobileOutputStreamを通して絵文字として出力される仕組みとなっています。
っで、長くなったので、Smart.Web.Mobileのソースの解説はまた明日(´д`;)
とりあえず試してみるだけなら、サンプルと今日の内容で大丈夫じゃないかと思いま。
*1:これもちょっと微妙な対応なんだけど…(´Д`)