 
Xamarin逆引きTips
Xamarin.FormsでWebビューを使用するには?
外部のWebページやローカルに配置されたHTMLコンテンツを簡単に表示できるWebViewコントロールをXamarin.Formsで使う方法を説明する。
 Xamarin.Formsで提供されている標準コントロールの一つに、WebViewコントロールがある。WebViewコントロールを使用すると、HTMLコンテンツを簡単に表示できる。なお、他のコントロールと同様に、このコントロールもネイティブなコントロールで構成されており、具体的には各プラットフォーム上のWebブラウザーコントロールとなっている。
 今回は、このWebViewコントロールの利用方法について解説する。
- *1 なお本Tipsは、Windows上でVisual Studio 2013を使用してXamarin.Forms開発をすることを前提としている(※編集部注: Mac上のXamarin Studioでも同様の手順で、本稿の内容が実現できることは確認している)。使用しているXamarin.Formsのバージョンは、プロジェクト作成時に利用されている「1.3.1.6296」である。
1. シナリオ
 WebViewコントロールは、URLを指定してWebページを表示したり、ローカルに配置されたリソースを表示したりできる。
本Tipsでは最初に、URLを指定して、外部のWebページを表示する方法を解説し、その後、HTMLソース(文字列)を直接指定する方法を説明する。
2. Xamarin.Formsプロジェクトの作成
メニューバーの[ファイル]-[新規作成]-[プロジェクト]から表示したダイアログで、[テンプレート]-[Visual C#]-[Mobile Apps]-[Blank App (Xamarin.Forms Portable)]を選択し、名前を「WebViewSample」として[OK]ボタンを押す。
3. WebViewコントロールの表示: WebページのURLの指定
 WebViewコントロールを表示するには、App.csファイルを以下のように修正する。
| using Xamarin.Forms; namespace WebViewSample {   public class App : Application {     public App(){       MainPage = new MyPage();     }     ……省略……   }   class MyPage : ContentPage {     public MyPage() {       var webView = new WebView { // <-1         Source = "http://xamarin.com" // <-2       };       Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0);       Content = webView; // <-3     }   } } | 
 WebViewコントロールを生成して(1)、Xamarin.Formsのページの唯一のコンテンツとして設定している(3)。
 なお、WebViewコントロールのSourceプロパティに、URLを指定*1することで、任意のWebページを表示させることができる(2)。
- *1 ここでのURL文字列は、UrlWebViewSourceオブジェクトに暗黙的に変換されている。
このコードを実行すると、次のような画面になる。
 
 
4. WebViewコントロールの表示:単一ファイルのHTMLソース指定
 任意のHTMLソースをWebViewコントロールに表示するには、App.csファイルを以下のように修正する。
| ……省略…… namespace WebViewSample {   ……省略……   class MyPage : ContentPage {     public MyPage() {       var html = new HtmlWebViewSource { // <-1         Html = "<html><body><h1>TEST</h1>サンプルページ</body></html>", // <-2       };       var webView = new WebView {         Source = html // <-3       };       Padding = new Thickness(0,Device.OnPlatform(20,0,0),0,0);       Content = webView;      }   } } | 
 最初に、HtmlWebViewSourceクラスのインスタンスを生成する(1)。
 HtmlWebViewSourceクラスには、Htmlというプロパティがあり、ここにHTMLソースをそのまま指定できる(2)。
 WebViewコントロールのSourceプロパティに、今、作成したHtmlWebViewSourceオブジェクトを設定することで、今度は任意のHTMLソースのWebページを表示することになる(3)。
このコードを実行すると、次のような画面になる。
 
 
5. WebViewコントロールの表示:複数ファイルのHTMLソース指定
通常、HTMLソースは、画像やスタイルシートなどのリンクを含んで複数のファイルで構成されている。例えば先のHTMLソースをスタイルシートや画像などの複数ファイルで構成されたものに変更すると、次のようになる。
| ……省略…… namespace WebViewSample{   ……省略……   class MyPage : ContentPage {     public MyPage() {       var html = new HtmlWebViewSource {         Html = "<html><head><link rel='stylesheet' href='css/my.css'></head><body><h1>TEST</h1><img src='Images/icon.png'>サンプルページ</body></html>", // <-1       ……省略……     }   } } | 
 Htmlプロパティに指定するHTMLソースに、スタイルシートへのリンクと画像ファイルのタグを追加した(1)。
このコードを実行すると、次のような画面になり、画像ファイルやスタイルシートへのリンクが無効になっているのが分かる。
 
 
画像へのリンクは、無効になっており、またスタイルシートも適用されていない。
6. 複数ファイルのHTMLソース: 基準ディレクトリ
 通常、HTMLでは、他のファイルへのリンクは、相対パスや絶対パスを使用して指定される。そして、HtmlWebViewSourceクラスには、BaseUrlというプロパティがあり、相対パスを指定する場合の基準ディレクトリを設定できるようになっている*2。
- *2 BaseUrlプロパティに指定できるのは、当該HTMLソースからの相対パスを指定するための基準ディレクトリである。このため、HTMLソース内では“/Images/icon.png”のような絶対パスの指定はできない。
しかし、基準ディレクトリとなる物理的な場所の指定は、プラットフォームごとに異なっており、残念ながらXamarin.Formsで共通的に記述する方法は提供されていない。このようなときの最も簡単な解決方法は、DependencyServiceを使用する方法である*3。DependencyServiceを使うことで、PCL(Portable Class Library)側ではインターフェースだけを定義して、その実体はプラットフォームごとに用意するのである。
- *3 DependencyServiceについての詳しい解説は、「Tips:Xamarin.Formsからプラットフォーム固有の機能を利用するには?(DependencyService利用)」を参照してほしい。
 DependencyServiceを使用してBaseUrlプロパティを設定するには、App.csファイルを以下のように修正する。
| ……省略…… namespace WebViewSample{   ……省略……   public interface IBaseUrl { string Get(); } // <-1   class MyPage : ContentPage {     public MyPage() {       var html = new HtmlWebViewSource {         Html = "<html><head><link rel='stylesheet' href='css/my.css'></head><body><h1>TEST</h1><img src='Images/icon.png'>サンプルページ</body></html>",         BaseUrl = DependencyService.Get<IBaseUrl> ().Get(), // <-2       };       ……省略……     }   } } | 
 1は、DependencyServiceで使用するインターフェースの定義である。任意のディレクトリ名を返すGetメソッドだけが定義されている。
 そして、これを利用して、BaseUrlプロパティに基準ディレクトリを指定している(2)。
7. 複数ファイルのHTMLソース: iOSにおける実装
 iOSでは、NSBundle.MainBundle.BundlePathプロパティでリソースのディレクトリを取得できる。これを使用して、インターフェースの実装を行うには、WebViewSample.iOSプロジェクトにBaseUrl.csファイルを追加して、次のように修正する。
| using Foundation; using WebViewSample.iOS; using Xamarin.Forms; [assembly: Dependency(typeof(BaseUrl))] // <-1 namespace WebViewSample.iOS {   public class BaseUrl : IBaseUrl { // <-2     public string Get() {        return NSBundle.MainBundle.BundlePath + "/Content"; // <-3     }   } } | 
 1は、DependencyServiceの属性指定である。また、定義したクラス(ここではBaseUrlとした)は、PCL側で定義したインターフェースを継承した形で定義されている(2)。これらは、共にDependencyServiceを使用するための定型句である。
 NSBundle.MainBundle.BundlePathプロパティで、リソースディレクトリの物理的なパスを取得できるので、そこに、“/Content”(=図5で自作したフォルダー名)を追加して基準ディレクトリとして返している。
基準ディレクトリに各ファイル配置した様子は次のようになる。

「Content」「css」「Images」フォルダーは手動で作成した。icon.pngファイルは、こちらを使用した。
なお、スタイルシートである、my.cssファイルには、次の内容を定義する。
| body{   background-color: #0C555D;   color: #F5F1E9; } h1 {   font-size: 80px;   color: #FF6860; } | 
このコードを実行すると、次のような画面になり、今度は、画像ファイルやスタイルシートへのリンクも有効になっているのが確認できる。

8. 複数ファイルのHTMLソース: Androidにおける実装
Androidでは、ファイル(raw asset files)を格納するために「Assets」フォルダーを使用する。Assetsフォルダーに置かれたファイルは、そのままの形で.apkファイルに含まれ、ファイルシステムにアクセスするのと同様に、「file:///android_asset/」でアクセスできる。
 これを使用して、インターフェースの実装を行うには、WebViewSample.DroidプロジェクトにBaseUrl.csファイルを追加して、次のように修正する。
| using WebViewSample.Droid; using Xamarin.Forms; [assembly: Dependency(typeof(BaseUrl))] // <-1 namespace WebViewSample.Droid {    public class BaseUrl : IBaseUrl { // <-2     public string Get() {       return "file:///android_asset/Content/"; // <-3     }   } } | 
1および2は、iOSの場合と同様で、DependencyServiceを使用するための定型句である。
物理的なディレクトリとして、Assetsフォルダーの下に“/Content”を追加して基準ディレクトリとして返している。
基準ディレクトリに各ファイル配置した様子は次のようになる。

iOSで使用した内容(図5)と同じものを配置している。
このコードを実行すると次のような画面になり、Androidでも、複数ファイルで構成されるHTMLソースのWebページが表示できることが確認できる。

9. まとめ
 WebViewコントロールを使用すると、Webページや、用意したHTMLコンテンツを表示するだけなら、非常に簡単に実装できることが分かる(しかし、イベントやメソッドの実装に関しては、逐次、進化してはいるようだが、まだまだ非力であることは否定できない)。
 WebViewコントロールの今後の拡充が楽しみである。
【コラム】iOSにおいても、BaseUrlプロパティは、正常に動作する
 Xamarinの開発者用ドキュメントでは、今回紹介したHtmlWebViewSourceクラスのBaseUrlプロパティが、iOSで正常に動作しないため、レンダラーを書くことで回避するようにアナウンスされている(次のリンク先)。
確かに、当初、そのようなバグがあったようだが、2015年4月14日現在、この問題は解消されている(図9)。このため、上記リンク先の回避策を講ずる必要はない。

※以下では、本稿の前後を合わせて5回分(第44回~第48回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
 
44. Xamarin.FormsでListViewのコンテキストアクションを使用するには?
リストの1つをスライド(iOS)もしくは長押し(Android)されたらメニューを表示する「コンテキストアクション」の基本的な使い方を説明する。
 
46. 【現在、表示中】≫ Xamarin.FormsでWebビューを使用するには?
外部のWebページやローカルに配置されたHTMLコンテンツを簡単に表示できるWebViewコントロールをXamarin.Formsで使う方法を説明する。
 
48. Xamarin.Formsでプラットフォームごとの微調整を行うには?
カスタムレンダラーやDependencyServiceの仕組みを使わず、Deviceクラスを利用してプラットフォーム間で異なる部分を微調整する方法を説明する。





 
 
