Xamarin.Forms Webビュー
1 Webビューとは
Xamarin.Formsで提供されているWebViewを使用すると、URLを指定したり、ローカルに作成したWebページなどを表示することができます。
Xamarin Developers Guide 「Working with WebView」
元々、各プラットフォームには、Webページを表示するブラウザベースのコントロールが用意されています。iOSでは、UIWebView、Androidでは、WebView、そして、WindowsPhoneではWebBrowserがそれにあたります。 そして、Xamarin.Formsでは、これらを共通コードから利用できるようにしています。
2 Webページの表示
WebViewのSourceプロパティにURLを指定することで、Webページを表示することができます。
public class App : Application { public App() { MainPage = new MyPage(); } } class MyPage : ContentPage { public MyPage() { // iOS の場合のみ、ステータスバーに重ならないように上に余白をとる Padding = new Thickness (0,Device.OnPlatform(20, 0, 0),0,0); // ページの唯一のコントロールとしてWebViewを配置する Content = new WebView { Source = "https://dev.classmethod.jp/" //表示するURLの指定 }; } }
Android | iOS | Windows Phone |
なお、iOS9以降では、ATS対応が必要です。下の図は、iOSプロジェクトのinfo.plist に「ATS を無効にする (非推奨)」という記述を追加した様子です。 ATSの扱いについては、下記をご参照ください。
[iOS 9] iOS 9 で追加された App Transport Security の概要
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
3 HTMLの表示
HTMLを表示させたい場合は、SourceプロパティにHtmlWebViewSourceオブジェクトを指定します。
public class App : Application { public App() { MainPage = new MyPage(); } } class MyPage : ContentPage { public MyPage() { // iOS の場合のみ、ステータスバーに重ならないように上に余白をとる Padding = new Thickness (0,Device.OnPlatform(20, 0, 0),0,0); var source = new HtmlWebViewSource { Html = "<meta charset='UTF-8'><h1>Developers.IO</h1>AWS/iOS技術者の必読メディア" }; // ページの唯一のコントロールとしてWebViewを配置する Content = new WebView { Source = source //HTMLを指定 }; } }
Android | iOS | Windows Phone |
HTML内からCSSや画像などの外部ファイルを指定したい場合は、基礎となるURL(プロパティBaseUrl)の指定が必要になります。
ディレクトリ構成は、ターゲットごと違うため、「ターゲット依存コード」としてこれを実装します。
参考:Xamarin.Forms トースト(DependencyService)
まずは、HTMLで、スタイルシートと画像を指定してみます。
public class App : Application { public App() { MainPage = new MyPage(); } } class MyPage : ContentPage { public MyPage() { // iOS の場合のみ、ステータスバーに重ならないように上に余白をとる Padding = new Thickness (0,Device.OnPlatform(20, 0, 0),0,0); var source = new HtmlWebViewSource { Html = "<html><head><meta charset='UTF-8'><link rel='stylesheet' href='my.css'></head><body><h1>Developers.IO</h1><img src='Images/classmethod.png'><br>AWS/iOS技術者の必読メディア</body></html>" }; // ページの唯一のコントロールとしてWebViewを配置する Content = new WebView { Source = source //HTMLを指定 }; } }
body{ font-size:20px; font-family:bold; text-shadow: 0 1px 0 #ccc, 0 2px 0 #c9c9c9, 0 3px 0 #bbb, 0 4px 0 #b9b9b9, 0 5px 0 #aaa, 0 6px 1px rgba(0,0,0,.1), 0 0 5px rgba(0,0,0,.1), 0 1px 3px rgba(0,0,0,.3), 0 3px 5px rgba(0,0,0,.2), 0 5px 10px rgba(0,0,0,.25), 0 10px 10px rgba(0,0,0,.2), 0 20px 20px rgba(0,0,0,.15); } h1 { font-size:50px; }
当然ですが、スタイルシートと画像は適用されません。
Android | iOS | Windows Phone |
そこで、HtmlWebViewSourceのBaseUrlを設定してみます。作業としては、ディレクトリ取得のメソッドをインターフェースとして定義し、それをDependencyService経由で使用します。
//共通インターフェース public interface IBaseUrl{ string Get(); }
var source = new HtmlWebViewSource{ Html = " //・・・省略・・・ //基礎となるURLを指定する BaseUrl = DependencyService.Get<IBaseUrl>().Get() };
続いて、ターゲットごとにインターフェースの実装を行います。
(1) Androidの場合
Androidでは、生ファイル (raw asset files) を格納するためにAssetsフォルダを使用します。
Assetsフォルダに保存されたファイルは、そのままの形で.apkファイルに含まれ、ファイルシステムにアクセスするのと同様に、file:///android_asset/でアクセスできます。
そこで対象となるファイルを図のように配置して、次のようにインターフェースを実装します。
using App1.Droid; using Xamarin.Forms; [assembly: Dependency(typeof(BaseUrl))] namespace App1.Droid { public class BaseUrl : IBaseUrl { public string Get() { return "file:///android_asset/"; } } }
スタイルシートと画像のパスが成立して、適用されていることを確認できます。
(2) iOSの場合
iOSにおいては、NSBundle.MainBundle.BundlePathから、ルート及びResourceの下にあるファイルにアクセスできます。
今回は、Contentというフォルダを作成しその中にリソースを置いてみました。
インターフェースの実装は、次のようになります。
[assembly:Dependency(typeof(BaseUrl))] namespace App1.iOS { class BaseUrl:IBaseUrl { public string Get(){ return NSBundle.MainBundle.BundlePath+"/Content"; } } }
実行結果は、次のとおりです。当初、バグのためレンダラー拡張によりLoadHtmlStringを修正する必要があるとドキュメントに記載されていたのですが、現在は問題なくなっています。
(3) WindowsPhoneの場合
WindowsPhoneの場合、カレントフォルダにそのままアクセスできるので、ファイルの配置及び、インターフェースの実装は、下記のようになります。
using App1.WinPhone; using Xamarin.Forms; [assembly:Dependency(typeof(BaseUrl))] namespace App1.WinPhone { class BaseUrl : IBaseUrl { public string Get() { return ""; } } }
ちょっとスタイルの扱いが違ってるようですが、一応実行できてます。なお、ドキュメントにはWindowsPhone8.1や10では、動作できないような記述があったのですが、WindowsPhone10のシュミレータでは問題を確認できませんでした。
4 ナビゲーション及びイベント
ナビゲーションには、次の機能が利用可能です。
GoForward() | 進む |
GoBack() | 戻る |
CanGoForward | 「進む」ことが可能かどうかのフラグ |
CanGoBack | 「戻る」ことが可能かどうかのフラグ |
また、イベントとしては、次のものが利用可能です。
Navigating | ページのロードが開始した時 |
Navigated | ページのロードが完了した時 |
ナビゲーション及びイベントを処理して、サンプルとして簡単なブラウザを作成してみました。
Android | iOS | Windows Phone |
書いたコードは、下記で全てです。
public class App : Application { public App() { MainPage = new MyPage(); } } class MyPage : ContentPage { public MyPage() { // iOS の場合のみ、ステータスバーに重ならないように上に余白をとる Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0); var webView = new WebView() { Source = "https://dev.classmethod.jp/", //起動時に表示するURLの指定 VerticalOptions = LayoutOptions.FillAndExpand // ナビゲーション部分以外は、全部WebViewのエリアとする }; //「戻る」ボタン var back = new Button { Text = " <<", IsEnabled = false // デフォルトで無効 }; back.Clicked += (s, e) => { // ボタンが押された時の処理 webView.GoBack(); // 戻る }; //「進む」ボタン var forword = new Button { Text = ">>", IsEnabled = false // デフォルトで無効 }; forword.Clicked += (s, e) => { // ボタンが押された時の処理 webView.GoForward(); // 進む }; // 検索バー var entry = new Entry { HorizontalOptions = LayoutOptions.FillAndExpand }; // 検索バーへの入力が完了した時 entry.Completed += (s, e) => { webView.Source = entry.Text;//入力されたURLへジャンプする }; // 上段のナビゲーション部分 var toolbar = new StackLayout { Orientation = StackOrientation.Horizontal, Children = { back,forword,entry // 「戻る」ボタン、「進む」ボタン、検索バーを横に配置する } }; Content = new StackLayout() { Children = { toolbar,webView} // ナビゲーション部分とWebViewを縦に配置する }; // ロード完了時のイベント処理 webView.Navigated += (s, e) => { back.IsEnabled = webView.CanGoBack; // CanGoBack==true の時、「戻る」ボタンを有効にする forword.IsEnabled = webView.CanGoForward;// CanGoForward==true の時、「 進む」ボタンを有効にする }; } }
5 まとめ
今回は、Xamarin.FormsのWebViewについて、その機能を一通り紹介しました。
Xamarin.Formsの誕生当初、このWebViewは、非常に機能が乏しく、いろいろとレンダラー拡張しないと使えないという印象がありましたが、最近では、かなり拡充されてきて、この悪いイメージも払拭されつつあると思います。
6 参考資料
この辺でXamarin導入による 効果と限界をしっかり把握してみよう MVP Community Camp 2015
Xamarin記事一覧(SAPPOROWORKSの覚書)