Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
Xamarin逆引きTips

Xamarin逆引きTips

Xamarin.FormsでAzureモバイルサービスによるToDoアプリを作成するには?

2015年7月23日

ひな型プロジェクトが用意されているXamarin.iOSやXamarin.Androidではなく、Xamarin.FormsからAzureモバイルサービスを活用する基本的な方法を、簡単なToDoアプリを題材に解説する。

古谷 誠進(@furuya02
  • このエントリーをはてなブックマークに追加

1. Microsoft Azureモバイルサービス(Mobile Services)

 Microsoft Azureモバイルサービスプレビュー版の新ポータルでは「Azure Mobile Apps」という名前に変更されているが、執筆時点でまだ現ポータルと同等の機能が使えないため、本稿では現ポータルを使用する)では、モバイルアプリ開発に使える各種SDKとプラットフォーム別のひな型プロジェクト(後述の図1)が用意されており、モバイルアプリの開発を容易に行うことができる。また、同サービスでは、初めて利用する場合でも簡単に開発が進められるように、導入用のチュートリアルが準備されており、そこにはXamarin用のものも含まれている。

 そして、このチュートリアル(現ポータルの場合新ポータルの場合)では、プロジェクトのひな型をダウンロードして進める手順が紹介されている(図1は現ポータルでモバイルサービスを作成した直後に表示されるチュートリアル)。

図1 モバイルサービス作成完了時に表示されるクイックスタートのページ

 しかし、ここでダウンロードできるプロジェクトは、Xamarin.iOS用とXamarin.Android用の2種類であり、残念ながら、Xamarin.Forms用は提供されていない。

 そこで今回は、このチュートリアルを真似た簡単なToDoアプリを題材に、Xamarin.Formsによるアプリ作成をステップバイステップで解説する。

  • *1 なお本Tipsは、Windows上でVisual Studio 2013を使用してXamarin.Forms開発をすることを前提としている(編集部注: Mac上のXamarin Studioでも同様の手順で、本稿の内容が実現できることは確認している)。使用しているXamarin.Formsのバージョンは、プロジェクト作成時に利用されている「1.3.1.6296」である。

2. モバイルサービスの設定

 Azureモバイルサービスを、現Azureポータルを使って作成する手順を説明する。

(1)モバイルサービスの作成

 現Azureポータルにアクセスし、以下の手順でモバイルサービスを作成する。

左の一覧から[モバイル サービス]を選択し、[+新規]ボタンを押す

左の一覧から[モバイル サービス]を選択し、[+新規]ボタンを押す

ポップアップされたウィンドウで[作成]ボタンを押す

下からポップアップされたウィンドウで[作成]ボタンを押す

[URL]欄には、自由に名前を指定できるが、世界で一意の名前にする必要がある。

[URL]欄には、自由に名前を指定できるが、世界で一意の名前にする必要がある。
また[地域]欄は(執筆時点で)「日本(西)」が選択可能である。
[データベース]欄は、すでに作成されているものを選択することも可能だが、
初めての場合は「無料の 20 MB SQL データベースの作成」を選択する。
[バックエンド]欄は、今回は「JavaScript」のままで変更してはいけない
(.NETバックエンドを選択すると、後述の[データ]タブが表示されないため)

データベースを新規に作成する場合、[データベースの設定の指定]ページが表示される。

データベースを新規に作成する場合、[データベースの設定の指定]ページが表示される。
ここでは、[サーバーログイン名]および[パスワード]を入力する

全ての入力が完了すると、新しく作成したモバイルサービスが一覧に表示されていることが確認できる

全ての入力が完了すると、
新しく作成したモバイルサービスが一覧に表示されていることが確認できる

図2 モバイルサービスの作成手順

(2)テーブルの作成

 モバイルサービスの一覧から、新規に作成したサービスを選択すると、そのサービスに関する各種の設定や状態を確認できる。次に、図3の手順でテーブルを作成する。

上部に並ぶタブメニューから[データ]を選択すると、[テープルの追加]というリンクが表示されるので、これをクリック

上部に並ぶタブメニューから[データ]を選択すると、
[テープルの追加]というリンクが表示されるので、これをクリック

[テーブル名]欄に「<b>ToDoItem</b>」と入力し、右下のチェックボタンを押す

[テーブル名]欄に「ToDoItem」と入力し、右下のチェックボタンを押す

しばらく待つと、テーブル一覧に、今作成したテーブルが追加されていることが確認できる

しばらく待つと、テーブル一覧に、今作成したテーブルが追加されていることが確認できる

図3 テーブルの作成手順

(3)テーブルへの列の追加

 続いて、今、作成したテーブルに列を追加する。テーブル一覧から「ToDoItem」をクリックし、それにより表示されるページで[列]タブメニューを開くと、図4のようにいくつかの列が自動的に作成されていることが確認できる。

図4 テーブルへの列の追加

 下段の[列の追加]ボタンを押すと、列を追加するためのポップアップが表示されるので(図5)、表1の2つを追加する。

データ型列名
String text
Boolean complete
表1 本稿で追加する2つの列
図5 列の追加覧(1)

「String」型の「text」列を追加

図5 列の追加覧(2)

「Boolean」型の「complete」列を追加

図5 列の追加

 追加が完了すると、列の一覧は、次のようになっている。

図6 追加された2つの列

(4)URLとアクセスキー

 ここまでで、モバイルサービスの準備は完了だが、作成するアプリからアクセスするために必要な情報として、URLおよびアクセスキーをコピーしておく。URLは、ダッシュボードの右枠に表示されている(図7)。また、下部の[キーの管理]ボタンをクリックすると「アクセスキー」を表示させることができる。

[キーの管理]ボタンをクリック

ダッシュボードの右枠に[モバイル サービス URL]が表示されている。
また、[アクセス キー]を取得するには[キーの管理]ボタンをクリックすればよい

図7 ダッシュボードからURLおよびアクセスキーを表示させている様子

3. Xamarin.Formsプロジェクトの作成

 メニューバーの[ファイル]-[新規作成]-[プロジェクト]から表示したダイアログで、[テンプレート]-[Visual C#]-[Mobile Apps]-[Blank App (Xamarin.Forms Portable)]を選択し、名前を「AzureToDoSample」として[OK]ボタンを押す。

図8 「Blank App (Xamarin.Forms Portable)」の新規作成

4. WindowsAzure.MobileServicesのインストール

 Azureモバイルサービスにアクセスするためには、NuGet版で提供されている、WindowsAzure.MobileServicesをインストールする必要がある。

 NuGetからパッケージをインストールするには、メニューバーの[ツール]-[NuGetパッケージマネージャ]-[パッケージ マネージャー コンソール]を選択し、表示されたコンソールで次のように入力する

パッケージ マネージャー コンソール
PM>Install-Package WindowsAzure.MobileServices -ProjectName AzureToDoSample
PM>Install-Package WindowsAzure.MobileServices -ProjectName AzureToDoSample.iOS
PM>Install-Package WindowsAzure.MobileServices -ProjectName AzureToDoSample.Droid
パッケージマネージャーコンソールで入力するInstallコマンド

 本来は、これでパッケージのインストールは完了なのだが、最新のWindowsAzure.MobileServicesでは、iOSで参照重複のエラーが出てコンパイルできない(図9)。

図9 コンパイルエラー

 このエラーを回避するためには、ソリューションエクスプローラーでプロジェクトの参照設定から、System.IOSystem.Runtaime、およびSystem.Threading.Tasksの3つを削除する必要がある。

図10 ソリューションエクスプローラーでプロジェクトの参照設定を削除する

5. メイン画面の作成

 ToDoアプリの画面を作成するには、App.csファイルを以下のように修正する。

C#
using Xamarin.Forms;

namespace WebViewSample {
  public class App : Application {
    public App() {
      if (Device.OS == TargetPlatform.Android) {
        MainPage = new NavigationPage(new MyPage()); // <-1
      } else {
        MainPage = new MyPage();
      }
    }

    ……省略……
  }
  class MyPage : ContentPage {
    public MyPage() {
      var entry = new Entry {         // <-2
        HorizontalOptions = LayoutOptions.FillAndExpand,
        Placeholder = "ここへ入力してください",
      };
      var buttonAdd = new Button {    // <-3
        Text = "追加",
        WidthRequest = 60,
      };

      var listView = new ListView(); // <-4

      Content = new StackLayout {     // <-5
        Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0),
        Children = {
          new StackLayout {          // <-6
            Padding = new Thickness(5),
            Orientation = StackOrientation.Horizontal,
            Children = {entry, buttonAdd }
          },
          listView
        }
      };
    }
  }

}
ToDoアプリの画面を表示するコード(App.cs)

 Entryコントロール(1)とButtonコントロール(2)を作成し、StackLayoutによって横に並べた(6)。

 また、ListViewコントロール(4)は、その下になるように配置されてる(5)。

 なお、Azureとの通信中を表わすためにインジケーターを表示する予定だが、Androidでは、NavigationPageでないと、このインジケーターが表示できない。このため、トップページとなるMyPageは、Androidの場合だけ、NavigationPageのルートページとして生成している(1)。

 このコードを実行すると、次のような画面になる。

図11 ToDoアプリの画面(iOS/Android)

【コラム】Androdiでのインジケーター

 Xamarin.Formsでは、Forms.PageIsBusyプロパティでインジケーターをON/OFFできる。しかし、Androidでは、このインジケーターが、ActionBarの位置に表示されるため、NavigationPageを使用しないと、インジケーターが確認できなくなる。

図12 Androidでインジケーターが表示されている画面
図12 Androidでインジケーターが表示されている画面

6. MobileServicesの初期化

 MobileServicesを使用するためには、各プラットフォームごとに初期化のコードが必要になる。初期化コードを追加するためには、AzureToDoSample.iOSプロジェクトのAppDelegate.csファイルを次のように修正する。

C#
……省略……
namespace AzureToDoSample.iOS {

    ……省略……

    public override bool FinishedLaunching(UIApplication app, NSDictionary options) {
      global::Xamarin.Forms.Forms.Init();

      Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init(); // <-1

      LoadApplication(new App());

      return base.FinishedLaunching(app, options);
    }
  }
}
MobileServicesを初期化するコード(AppDelegate.cs)

 FinishedLaunchingメソッドにおいて、Xamarin.Formsの初期化コードの直後に、CurrentPlatform.Init()を追加する(1)。

 同様に、AzureToDoSample.DroidプロジェクトのMainActivity.csファイルも次のように修正する。

C#
……省略……
namespace ToDoSample.Droid {
  ……省略……

    protected override void OnCreate(Bundle bundle) {
      base.OnCreate(bundle);

      global::Xamarin.Forms.Forms.Init(this, bundle);
      Microsoft.WindowsAzure.MobileServices.CurrentPlatform.Init(); // <-1
      LoadApplication(new App());
    }
  }
}
MobileServicesを初期化するコード(MainActivity.cs)

 OnCreateメソッドにおける、Xamarin.Formsの初期化コードの直後に、CurrentPlatform.Init()を追加する(1)。

7. データクラスの定義とリストビューへのバインド

 Azureモバイルサービス上で作成したテーブルにアクセスするため、AzureToDoSampleプロジェクトにToDoItem.csファイルを追加して、次のように修正する。

C#
using Newtonsoft.Json;

namespace AzureToDoSample {
  class ToDoItem {
    public string Id { get; set; }

    [JsonProperty(PropertyName = "text")] // <-1
    public string Text { get; set; } // <-2

    [JsonProperty(PropertyName = "complete")]
    public bool Complete { get; set; } 
  } 
}
テーブルにアクセスするためのデータクラス(ToDoItem.cs)

 データクラスは、ToDoItemとして定義した。ToDoItemクラスでは、キーとなるIdプロパティと、追加した列にアクセスするTextプロパティおよびCompleteプロパティを定義している。

 JsonProperty属性を使用すると、テーブル上の列名を指定できるため(1)、プロパティ名を自由に指定できる。ここでは、C#の命名規約に従うため、キャメルケースにしている(2)。

 次に、作成したToDoItemクラスをリストビューのアイテムとしてひも付けるには、App.csファイルを次のように修正する。

C#
using System.Collections.ObjectModel;
using Xamarin.Forms;

namespace AzureToDoSample {

  ……省略……

  class MyPage : ContentPage {
    
    readonly ObservableCollection<ToDoItem> _ar = new ObservableCollection<ToDoItem>(); // <-1
    
    public MyPage() {

      ……省略……

      var listView = new ListView() {
        ItemsSource = _ar, // <-2
        ItemTemplate = new DataTemplate(typeof (TextCell)), // <-3
      };
      listView.ItemTemplate.SetBinding(TextCell.TextProperty, "Text");// <-4

      ……省略……
    }
  }
}
データクラスをリストビューのアイテムとして紐づけるコード(App.cs)

 ToDoItemクラスは、ObservableCollectionクラスを使用してコレクションとしてインスタンス化した(1)。

 インスタンス化したデータは、リストビューのItemSourceプロパティにセットする(2)。

 表示用のテンプレートには、汎用のTextCellを使用することとし(3)、TextCell.TextPropertyToDoItemクラスのTextプロパティをバインドした。

8. MobileServiceClientの生成

 MobileServiceClientクラスをインスタンス化するには、App.csファイルを次のように修正する。

C#
using System.Collections.ObjectModel;
using Microsoft.WindowsAzure.MobileServices;
using Xamarin.Forms;

namespace AzureToDoSample {

  ……省略……

  class MyPage : ContentPage {
    
    const string ApplicationUrl = "https://xamarinformstodosample.azure-mobile.net/"; // <-1
    const string ApplicationKey = "xxxxxxxxxxxxxxxxxxxxxxxxxx"; // <-2
    readonly MobileServiceClient _client = new MobileServiceClient(ApplicationUrl, ApplicationKey);  // <-3
    
    ……省略……
  }
}
MobileServiceClientクラスをインスタンス化するコード(App.cs)

 URL(1)およびアクセスキー(2)は、モバイルサービスを作成した際に、管理ポータルで確認したものだ。

 この2つのキーを使用して、MobileServiceClientクラスをインスタンス化する(3)。

9. データの追加

 いよいよ、Azureモバイルサービスへのアクセスである。[追加]ボタンを押したときに、データを追加するには、App.csを次のように修正する。

C#
using System;
using System.Collections.ObjectModel;
using Microsoft.WindowsAzure.MobileServices;
using Xamarin.Forms;

namespace AzureToDoSample {

  ……省略……

   class MyPage : ContentPage {

    ……省略……
    public MyPage() {
      ……省略……
      var buttonAdd = new Button() {
        Text = "追加",
        WidthRequest = 60,
      };
      buttonAdd.Clicked += (s, a) => Add(entry); // <-1

      ……省略……
    }

    async void Add(Entry entry) {
      if (!String.IsNullOrEmpty(entry.Text)) {
        IsBusy = true;       // <-2

        var item = new ToDoItem { Complete = false, Text = entry.Text }; // <-3
        await _client.GetTable<ToDoItem>().InsertAsync(item); // <-4

        _ar.Insert(0, item); // <-5
        entry.Text = "";
        IsBusy = false;      // <-6
      }
    }
  }

}
ボタンを押したときに、データを追加するコード(App.cs)

 [追加]ボタンのクリックイベントでAddメソッドが実行されるように指定した(1)。

 Addメソッドでは、Entryコントロールに入力された文字列を使用して、ToDoItemオブジェクトを生成し(3)、MobileServicesInsertAsyncメソッドを使用して、Azure上のデータベースに追加する(4)。

 なお、クライアント側は、ListViewコントロールのデータソースであるコレクションに同オブジェクトを追加し、データバインディングで表示を更新する(5)。

 処理の前後では、インジケーターを表示している(2 6)。

 このコードを実行すると、次のような画面になる。

図13 文字列を追加している画面(1)

文字列を入力して[追加]ボタンを押す

図13 文字列を追加している画面

10. データの削除

 リストビューをタップしたときに、データを削除するには、App.csファイルを次のように修正する。

C#
……省略……

namespace AzureToDoSample {

  ……省略……

  class MyPage : ContentPage {
    
    ……省略……
    public MyPage() {

      ……省略……
      var listView = new ListView() {
        ItemsSource = _ar,
        ItemTemplate = new DataTemplate(typeof (TextCell)),
      };
      listView.ItemTemplate.SetBinding(TextCell.TextProperty, "Text");
      listView.ItemTapped += async (s, a) => { 
        if (await DisplayAlert("確認", "削除して宜しいですか?", "OK", "Cancel")) { // <-1
          Del((ToDoItem)a.Item); // <-2
        };
      };
       ……省略……
    }

    async void Del(ToDoItem item) {
      IsBusy = true;        // <-3

      item.Complete = true; // <-4
      await _client.GetTable<ToDoItem>().UpdateAsync(item); // <-5

      _ar.Remove(item);     // <-6

      IsBusy = false;       // <-7
    }

     ……省略……
  }

}
リストビューをタップしたときに、データを削除するコード(App.cs)

 リストビューのタップイベントで、実行の確認をした後(1)、Delメソッドが実行されるように指定した(2)。

 Delメソッドでは、リストビューから得たToDoItemオブジェクトのCompleteプロパティをtrueに変更し(4)、MobileServicesUpdateAsyncメソッドを使用して、Azure上のデータベースを更新する(5)。

 なお、追加と同じようにクライアント側は、データバインディングで更新されている(6)。

 インジケーターの処理も同じである(3 7)。

 このコードを実行すると、次のような画面になる。

図14 文字列を削除している画面(1)

項目をタップする

図14 文字列を削除している画面

11. データの更新

 リストビューの内容をサーバー上のデータに合わせて更新するためには、App.csファイルを以下のように修正する。

C#
……省略……

namespace AzureToDoSample {

  ……省略……

  class MyPage : ContentPage {

      ……省略……
      public MyPage() {

        ……省略……
        Refresh(); // <-1
    }

    async void Refresh() {
      IsBusy = true;

      _ar.Clear(); // <-2

      var result = await _client.GetTable<ToDoItem>().Where(item => item.Complete == false).ToListAsync(); // <-3
      result.Reverse(); 
      foreach (var a in result) { // <-4
        _ar.Add(a);
      }
      IsBusy = false;
    }
  }

}
起動時に表示を更新するコード(App.cs)

 メインページのコンストラクターで、Refreshメソッドを呼び出している(1)。

 Refreshメソッドでは、いったんデータソースをクリアする(2)。

 MobileServicesGetTableメソッドを使用して、Azure上のデータベースからをcomplete列がfalseのものだけを検索し(3)、あらためてデータソースを初期化している(4)。

 これにより、アプリ起動時に、前回の状態が復元できるようになる。

12. まとめ

 今回は、Azureモバイルサービスを使用した、簡単なToDoアプリの作成を紹介した。Azureモバイルサービスでは、今回使用したデータ保存の機能だけでなく、認証や通知なども簡単に利用できるようになっている。今後、これらの機能についても機会があれば紹介したいと考えている。

【コラム】自動で追加されるカラム

 Azureモバイルサービスでは、テーブル内のカラムは、自動的に追加される。本記事では、最初に必要なカラムを手動で追加したが、データにアクセスするクラスで、適切なプロパティを定義すれば、最初にアクセスした時点で自動的にカラムが追加される。

 次のようにデータクラスにDmyプロパティを追加してアクセスするだけで、列が追加されているのを確認できる。

C#
using Newtonsoft.Json;

namespace AzureToDoSample {
  class ToDoItem {
    ……省略……

    [JsonProperty(PropertyName = "dmy")] // <-追加
    public bool Dmy { get; set; }        // <-追加
  }
}
Dmyプロパティを追加したコード(ToDoItem.cs)
図15 Dmy列が追加されている状態

列が増える前のデータは、同カラムがNULLになっている。

 一度追加されたカラムは、データベースの仕様上、自動的に削除されることは無い。従って、うっかりクラスのプロパティ名を間違えてアクセスしたりすると、不要なカラムがごみとなって残ってしまう事になる。ポータルサイトからもデータベースのレコードなどを確認することが可能なので、リリース前には、再確認することが重要である。

※以下では、本稿の前後を合わせて5回分(第54回~第58回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

Xamarin逆引きTips
54. コードを書く前に正規表現をテストするには?(.NET/Xamarin対応)

.NET/Monoの基本クラスライブラリを使って正規表現を書く場合、そのテストはどうする? Xamarin Studioの正規表現ツールキットを使って手軽に行う方法を紹介。

Xamarin逆引きTips
55. MvvmCrossでカスタムコントロールをTwo-Wayバインディングに対応させるには?

MvvmCrossでのiOS/Androidアプリ開発において、カスタムビュークラスをTwo-Wayバインディングに対応させる方法を解説する。

Xamarin逆引きTips
56. 【現在、表示中】≫ Xamarin.FormsでAzureモバイルサービスによるToDoアプリを作成するには?

ひな型プロジェクトが用意されているXamarin.iOSやXamarin.Androidではなく、Xamarin.FormsからAzureモバイルサービスを活用する基本的な方法を、簡単なToDoアプリを題材に解説する。

Xamarin逆引きTips
57. MvvmCrossで画像をバインディングするには?

MvvmCrossでのiOS/Androidアプリ開発において、画像のURLをViewへバインディングできるMvxImageViewの使い方を説明する。

Xamarin逆引きTips
58. MvvmCrossで文字列をローカライズ(多言語化)するには?

MvvmCrossでのiOS/Androidアプリ開発において、ViewModelの文字列リソースを多言語化してローカライズする方法を解説する。

サイトからのお知らせ

Twitterでつぶやこう!