Xamarin逆引きTips
MvvmCrossでWebBrowserプラグインを使用するには?
WebBrowserプラグインを追加・利用する例を通じて、MvvmCrossでのiOS/Androidアプリ開発におけるMvvmCrossプラグインの基本的な使い方を説明する。
MvvmCrossには非常に多くの機能が含まれているが、特に各プラットフォーム固有の処理を共通処理として扱えるものは「プラグイン」として分割して提供されている。
今回はMvvmCrossのプラグイン機構の概略と、標準のプラグインをNuGetで導入して使用する方法を解説する。
- *1 なお、本TipsはMac OS X(10.10.3), Xamarin Studio(5.9.1), MvvmCross(3.5.0)で動作を確認している(※編集部注: Windows上のVisual Studioでも同様の手順で、本稿の内容が実現できることは確認している)。
プラグイン機構を使用したプラットフォーム固有処理の共通化と再利用
プラットフォームごとの固有の処理は、iOS/Androidでそれぞれ記述して対応することもできる。しかしながらプラットフォーム固有の処理を一般化したインターフェースを用意しておき、ViewModelやServiceから一様に扱えば、ビジネスロジックは1度記述すればよくなり、生産性を向上できる。さらに、加速度センサー、位置情報の取得、Safariなどの標準ブラウザー起動といった処理は、どんなアプリでも使用する一般的なタスクのため、再利用性を上げることで多くのアプリで使用できる。
MvvmCrossには、プラットフォームごとの固有処理をはじめとした、各種処理を再利用するための機構としてプラグインが用意されている。MvvmCrossのプラグイン機構は一定の決まりで実装されたアセンブリを、起動時にMvvmCrossが自動的に読み込み、起動コードを実行するようになっている。
以下の図は実際のMvvmCrossプラグインの実装だが、Coreに当たるPCL(Portable Class Library)にPluginLoader
クラスが、各プラットフォーム固有実装部分にはPlugin
クラスがあることが分かる。Plugin.Load()
メソッドが実際の処理の起点となり、多くのプラグインはこの部分でIoCコンテナー(DIコンテナー)にクラスを登録するが、コンバーターを使えるようにしたり、リソースをロードしたりするものもある。
Coreに当たるPCLにPluginLoader
というクラスと、プラットフォーム固有実装部分にPlugin
というクラスがあることが分かる。Plugin.Load()
メソッドがプラグインの処理の起点となる。
MvvmCross標準プラグイン
MvvmCrossが提供するプラグインは本体同様、NuGetで提供されている。以下の表はMvvmCrossが標準で提供するプラグインの一覧だが、標準でも多くの機能が提供されていることが分かる。また、MvvmCross自体の一部機能も、プラグインのインストールを前提としているものもある。
プラグイン名 | 機能概要 | iOS | Android | Windows Phone | Windows Storeアプリ | Windowsデスクトップ(WPF) |
---|---|---|---|---|---|---|
■標準機能の拡張 | ||||||
Messenger | Messengerパターンに使用するMessenger機能を提供する | ● | ● | ● | ● | ● |
Color | MvxColorを各プラットフォームのColorオブジェクトに変換するコンバーターを提供する | ● | ● | ● | ● | ● |
Visibility | 表示状態へのコンバーターを提供する | ● | ● | ● | ● | ● |
JsonLocalisation | JSONファイルを使用したテキストリソースローカライズ機能を提供する | ● | ● | ● | ● | ● |
ResourceLoader | アプリのリソースとして埋め込まれているファイルへのアクセスを提供する | ● | ● | ● | ● | ● |
File | ファイルの作成・保存機能を提供する | ● | ● | ● | ● | ● |
DownloadCache | ダウンロードキャッシュ機能を提供する(MvxImageViewクラスの内部で使用される) | ● | ● | - | - | - |
■プラットフォーム機能やセンサーの呼び出し | ||||||
Accelerometer | 加速度センサーの値を取得する | ● | ● | ● | ● | ● |
Location | 位置情報へのアクセスを提供する | ● | ● | ● | ● | ● |
Network | ネットワークへの疎通判定(Reachability)機能を提供する | ● | ● | ● | ● | ● |
SoundEffects | 音の再生機能を提供する | - | - | ● | - | - |
■外部アプリとの連携、標準ダイアログの呼び出し | ||||||
PhoneCall | 電話発信機能を提供する | ● | ● | ● | ● | - |
メール送信画面の起動を提供する | ● | ● | ● | ● | ● | |
WebBrowser | 標準ブラウザーの起動機能を提供する | ● | ● | ● | ● | - |
PictureChooser | 写真の選択ダイアログを表示する | ● | ● | ● | ● | - |
Share | ソーシャルへのシェア機能を提供する | ● | ● | ● | ● | ● |
Bookmarks | ブラウザーブックマークへの登録機能を提供する | - | - | ● | - | - |
全てのプラットフォームで対応しているわけではないものや、プラットフォームによっては実装が不十分な場合もある。
先述の通り、ほとんどのプラグインはIoCコンテナーにオブジェクトを追加するが、「Tips:MvvmCrossでカスタムコンバーターを作成するには?」でも紹介したColorプラグインとVisibilityプラグインは特殊で、コンバーターが追加される。
プラグインの追加方法
サンプルプロジェクトを通じてプラグインの使い方を確認していこう。今回はMvvmCross標準のWebBrowserプラグインを使用して標準ブラウザーを起動させるプログラムを作る。
プロジェクトの作成
「Tips:MvvmCrossのプロジェクトをセットアップするには?」の手順に従い、MvvmCrossプロジェクトを作成する。ソリューション名は「OpenBrowserSample」と設定する(※以下のコラムでは、「MvvmCrossSample」というソリューション名で作成しており、名前に違いがあるので注意してほしい)。
【コラム】Xamarin Studio 5.9でのプロジェクト新規作成ダイアログの変更
Xamarin Studio 5.9ではプロジェクト新規作成時のダイアログが変更されており、ウィザード形式になり分かりやすくなった。また、ストアに公開するに当たって適切に設定すべきBundle Identifier(iOS)およびパッケージID(Android)の入力が、そのウィザードで求められるようになっている。これにより、「Tips:MvvmCrossのプロジェクトをセットアップするには?」の当初の説明からプロジェクトの作成について変更が生じている(※編集部注: 該当記事も新ダイアログによる操作方法の説明を更新した)。以下の内容はリンク先の記事に対する差分となる。
まず、ソリューションおよび、共通部分となるCoreプロジェクトを作成する。
具体的には、Xamarin Studioで(メニューバーにある)[ファイル]メニューの[新規]から[ソリューション]を選択して、ソリューション新規作成用のダイアログ(図A)を開く。プロジェクトの種類から[その他]の[.NET]にある[Portable Library]を選択し、[Next]ボタンを押す。
ダイアログ画面が[Configure your project](図B)になるので、[プロジェクト名]を「MvvmCrossSample.Core」とし、[Solution Name]は「MvvmCrossSample」とする。[位置]のテキストフィールドの下にある[Create a project within solution directory.]にチェックが入っているかを確認し、最後に[作成]ボタンを押せば、実際にソリューションとCoreプロジェクトが作成される。
次に、作成されたソリューションにiOSアプリのプロジェクトを追加する。
これには、[ソリューション]ビューのソリューション項目を右クリックし、(表示されるコンテキストメニューの)[追加]から[新しいプロジェクトを追加]を選択する。それにより表示されるダイアログ(図C)で、プロジェクトの種類から[iOS]の[App]にある[空のプロジェクト]を選択し、[Next]ボタンを押す。
ダイアログ画面が[Configure your iOS app](図D)になるので、[App Name]を「MvvmCrossSample」とし、[Identififer]はiOSのApplication Identifierとなるので、所有しているドメインの逆順表記+アプリケーション名とする命名規則に沿って指定する(例えば、「jp.co.fenrir.mvvmcrosssample」などとする)。[Devices]は今回の開発ではiPadは対象外とするため、iPadのチェックを外す。[ターゲット]のiOSは、サポートしたい下限のiOSを選択する。入力が完了すれば[Next]ボタンを押す。これにより図Bと同じような「プロジェクト名の設定」をするための[Configure your new project]画面になるので、そこで[プロジェクト名]を「MvvmCrossSample.Touch」として、最後に[作成]ボタンを押せば、実際にiOSプロジェクトが作成される。
さらに、AndroidアプリのプロジェクトをiOSと同様の手順で追加する。プロジェクトの種類は[Android]-[App]から[Android App]だ。[Configure your Android app]の画面(図E)では、[App Name]を「MvvmCrossSample」とし、[Identififer]はAndroidのパッケージ名となるので、所有しているドメインの逆順表記+アプリケーション名とする命名規則に沿って指定する(iOS同様、「jp.co.fenrir.mvvmcrosssample」などとするとよいだろう)。[Target Platforms]には、どのAndroidバージョンで使用できるアプリを作るかを指定する(※各選択肢の意味は次の表を参照されたい)。MvvmCrossは、3.5からAndroid 2.3に対するサポートが終了しているため、実際は[Modern Development]を選択する場面が多くなるだろう。
Target Platforms の選択 | 対応バージョン |
---|---|
Modern Development | Android 4.4 (API Level 19) をターゲットとし、Android 4.1 (API Level 16) 以上で動作する |
Maximum Compatibility | Android 4.4 (API Level 19) をターゲットとし、Android 2.3 (API Level 10) 以上で動作する |
Latest and Greatest | 最新SDKをターゲットとし、Android 5.0 (API Level 21) 以上で動作する |
その次の画面[Configure your new project]では、[プロジェクト名]として「MvvmCrossSample.Droid」として作成する。
プラグインの導入
プロジェクトが作成されたら、プラグインを追加する。今回はMvvmCross標準の「MvvmCross - WebBrowser Plugin」を追加する。
[ソリューション]ビューの「Core」プロジェクト項目を右クリックし、[追加]から[Add NuGet Packages]を選択して、ダイアログ(図2)を開く。右上の検索フィールドから「MvvmCross」という名前でパッケージを検索すると、MvvmCrossに関連するパッケージが列挙される。このリストの中から[MvvmCross - WebBrowser Plugin]を選択してインストールする。現在は独自フォークされたMvvmCrossとそのパッケージも上がっているので、公式のプラグインを追加する場合は、パッケージIDがMvvmCross.HotTuna.Plugin
で始まることを確認しておくとよい。
MvvmCross - WebBrowser Plugin
を追加する。公式のプラグインを追加する場合はパッケージIDがMvvmCross.HotTuna.Plugin
であることを確認すること。
この操作を用意した全てのプロジェクト(つまりiOSやAndroidのプロジェクト)にも行う。各プラットフォームのプロジェクトへの追加を行うと、「Bootstrap」というフォルダーができ、「WebBrowserPluginBootstrap.cs」というファイルができている(図3)。このクラスはMvxPluginBootstrapAction
クラスを継承したもので、MvvmCrossは起動時にこのクラスを検索してプラグインをロードするため、削除しないようにする。
Bootstrapフォルダーが作られ、その中にPluginBootstrap
クラスが作成される。プラグインの読み込みに使用されるので削除しないこと。
Coreプロジェクトの実装
FirstViewModel
クラスを以下のように実装する。
using Cirrious.MvvmCross.ViewModels;
using Cirrious.MvvmCross.Plugins.WebBrowser;
namespace OpenBrowserSample.Core.ViewModels
{
public class FirstViewModel : MvxViewModel
{
readonly IMvxWebBrowserTask _webBrowserTask;
// 1
public FirstViewModel(IMvxWebBrowserTask webBrowserTask)
{
_webBrowserTask = webBrowserTask;
}
// 2
string _url = "https://www.buildinsider.net/";
public string Url
{
get { return _url; }
set
{
_url = value;
RaisePropertyChanged(() => Url);
}
}
MvxCommand _openBrowserCommand;
public MvxCommand OpenBrowserCommand
{
get
{
// 3
return _openBrowserCommand ??
(_openBrowserCommand = new MvxCommand(() => _webBrowserTask.ShowWebPage(Url)));
}
}
}
}
|
まず、引数にWebBrowser Pluginが提供するIMvxWebBrowserTask
を指定したコンストラクターを定義している。このようにすることで、ViewModelが作成されるときにIoCコンテナーに入っているプラットフォームごとのIMvxWebBrowserTask
インターフェースの実装が渡されるので、この先の処理のためにフィールド変数に格納しておく(1)。
次に、開くURLを入力するためのテキストフィールドとなるUrl
プロパティを定義した(2)。
また、ボタンをタップしたときの処理として、OpenBrowserCommand
を定義した(3)。ここではIMvxWebBrowserTask
が提供するShowWebPage
メソッドを実行して、Url
プロパティにセットされているURLを標準ブラウザーで開くように実装している。
Touchプロジェクトの実装
iOS側の実装は、「Tips:MvvmCrossで画面遷移するには?」で紹介した.xibファイルを使う方法で行う。このページを参考にFirstViewを作成し、URL入力用にText Field(UITextField=iOS標準の単一行テキスト入力コンポーネント)と、ブラウザー起動用にButton(UIButton=iOS標準のボタン)を画面上に配置し、それぞれUrlTextField
とOpenBrowserButton
としてアウトレットを作成する(図4)。
次にバインディングを定義する。ViewsフォルダーのFirstView.cs
ファイルを次のように修正する。
using Cirrious.MvvmCross.Touch.Views;
using Cirrious.MvvmCross.Binding.BindingContext;
using OpenBrowserSample.Core.ViewModels;
namespace OpenBrowserSample.Touch.Views
{
public partial class FirstView : MvxViewController // 1
{
public FirstView() : base("FirstView", null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// 2
var set = this.CreateBindingSet<FirstView, FirstViewModel>();
set.Bind(UrlTextField).To(vm => vm.Url);
set.Bind(OpenBrowserButton).To(vm => vm.OpenBrowserCommand);
set.Apply();
}
}
}
|
継承元のクラスをMvxViewController
へ変更し(1)、バインディングを定義している(2)。
Droidプロジェクトの実装
Droidプロジェクトについてもレイアウトを作成し、バインディングを定義する。
これには、[ソリューションビュー]からDroidプロジェクトのResources-layoutフォルダーにあるFirstView.axmlファイルを次のように編集する。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<!-- 1 -->
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
local:MvxBind="Text Url" />
<!-- 2 -->
<Button
android:text="Open Browser"
android:layout_width="match_parent"
android:layout_height="wrap_content"
local:MvxBind="Click OpenBrowserCommand" />
</LinearLayout>
|
URL入力用のEditTextを用意して、Text
プロパティをViewModelのUrl
プロパティへバインディングし(1)、ブラウザー起動用のButton(2)を作り、ClickイベントにViewModelのOpenBrowserCommand
をバインディングしている2。
アプリケーションの実行
この状態でアプリを実行すると、URL入力用のテキストフィールドと、ブラウザー起動用のボタンが表示される。デフォルトでURLが入力されているので、そのままボタンをタップするとiOSではSafariが、Androidではユーザーがデフォルト設定しているブラウザーが起動してBuild Insiderのトップページが表示される。
ViewModelでの記述のみで、目的としている標準ブラウザーの起動をさせることができた。
■
このように、プラグインを活用することで、クロスプラットフォーム開発の効率を向上させることができる。プラットフォーム固有の実装をする前に、「プラグインが利用できないか」もしくは「新規にプラグインを作成できないか」を検討してみてほしい。
【コラム】コミュニティで提供されているプラグイン
NuGetにはMvvmCrossの機能として提供されているものの他、コミュニティによって作成されたプラグインも存在している。例えば、以下のようなものである。
- MvvmCross SMS Plugin (Cheesebaron.MvvmCross.Plugins.Sms)
- MvvmCross Signature Pad Plugin (Acr.MvvmCross.Plugins.SignaturePad)
- MvvmCross Device Information (Acr.MvvmCross.Plugins.DeviceInfo)
こういったプラグインも今回の方法で読み込めるが、プラグインの使用方法などは追加するときには分からないことが多い。多くの場合はnuget.orgで当該のプラグインを検索し、詳細ページからProject Siteを開くことでそのプラグインの配布元サイトを参照できるので、ドキュメントはここから得られる。
なお、NuGetにはMvvmCrossバージョン1.x系をターゲットとしたプラグインも残っているので、間違って追加しないように注意が必要となる。
※以下では、本稿の前後を合わせて5回分(第51回~第55回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
51. MvvmCrossでカスタムコンバーターを作成するには?
MvvmCrossでのiOS/Androidアプリ開発において、バインディングする値を変換できるカスタムコンバーターの使い方を説明する。
52. Xamarin.FormsでTwitterクライアントを作成するには?
TwitterのAPIを扱えるライブラリであるCoreTweetを使用して、Twitterデータを検索するアプリを作成。CoreTweetの導入と、検索したテキストの表示までを紹介する。
53. 【現在、表示中】≫ MvvmCrossでWebBrowserプラグインを使用するには?
WebBrowserプラグインを追加・利用する例を通じて、MvvmCrossでのiOS/Androidアプリ開発におけるMvvmCrossプラグインの基本的な使い方を説明する。
54. コードを書く前に正規表現をテストするには?(.NET/Xamarin対応)
.NET/Monoの基本クラスライブラリを使って正規表現を書く場合、そのテストはどうする? Xamarin Studioの正規表現ツールキットを使って手軽に行う方法を紹介。
55. MvvmCrossでカスタムコントロールをTwo-Wayバインディングに対応させるには?
MvvmCrossでのiOS/Androidアプリ開発において、カスタムビュークラスをTwo-Wayバインディングに対応させる方法を解説する。