June 2017

Volume 32 Number 6

Xamarin - Visual Studio Mobile Center による認証とデータ アクセス

Alessandro Del Del

Connect(); 2016 において、マイクロソフトは Visual Studio Mobile Center (mobile.azure.com、英語) のプレビュー版を公開しました。Visual Studio Mobile Center は新しいポータルで、開発者が DevOps 手法でモバイル アプリをビルドするために必要なすべて (バックエンド サービスや継続的インテグレーションから分析、テスト自動化まで) を 1 か所で提供します。Visual Studio Mobile Center には、Microsoft Azure Mobile Apps、Visual Studio Team Services、Xamarin Test Cloud、HockeyApp を通じてマイクロソフトが提供しているツールとサービスがまとめられます。Visual Studio Mobile Center で利用できるものの概要については、Thomas Dohmke のコラム「モバイル DevOps - Visual Studio Mobile Center の調査」(bit.ly/2f7a8Wk) をご覧ください。

ここでは、認証と表 (テーブル) についての実践的な手法を中心に取り上げ、Xamarin.Forms でビルドしたサービスを、Android と iOS で実行されるクロスプラットフォーム アプリから利用する方法を説明します。サンプル アプリでは、ユーザーが購入した書籍の一覧を表示、保存します。また、コードを再利用しやすいように、モデル - ビュー ビューモデル (MVVM:Model-View-ViewModel) パターンに基づたアプリにしています。今回説明する機能の一部には、Azure サブスクリプションが必要です。Azure サブスクリプションをまだ利用していない方は、azure.microsoft.com で無料試用を申請できます。サンプル アプリをビルドするには、最新の Xamarin 拡張機能をインストールした Visual Studio 2017 または 2015 が必要です。無償の Community エディションは visualstudio.com からダウンロードできます。

Visual Studio Mobile Center へのアプリの追加

Visual Studio Mobile Center のサービスを利用する場合、まず、新しいアプリをポータルに関連付ける必要があります。そのためには、ポータル (mobile.azure.com、英語) に参加して、Microsoft アカウントまたは GitHub アカウントでサインインします。Mobile Center のウェルカム ページに、[Add new app] (新しいアプリの追加) ボタンが表示されます。図 1 に示すように、このボタンをクリックしたら、アプリ名、説明 (省略可)、ターゲット OS、開発プラットフォームを指定します。

Visual Studio Mobile Center へのアプリの追加
図 1 Visual Studio Mobile Center へのアプリの追加

本稿執筆時点では、Mobile Center のサポート対象は iOS アプリケーションと Android アプリケーションだけです (Windows のサポートも予定されています)。また、利用できる開発プラットフォームの一覧は選択した OS によって変わります。図 1 に示すように情報を入力し、[Xamarin] を選択して、[Add new app] (新しいアプリの追加) をクリックします。Xamarin プロジェクトのビルドに使用できる Mac コンピューターが手元にある場合は Android ではなく iOS を選びます。今回のサンプル コードはどちらのプラットフォームでも実行できます。また、両方の OS で分析レポートとクラッシュ レポートをサポートできるよう、アプリを 2 回関連付けることもできます。

この後、Visual Studio Mobile Center では、Mobile Center SDK NuGet パッケージを使って Xamarin アプリ (Xamarin.Forms など) に分析レポートとクラッシュ レポートを含める方法が表示されます。これについてはサンプル コードで後ほど行うので、先に進みましょう。

表の作成

これで、新しい表をセットアップして書籍の一覧を保存できるようになります。ツール バーの [Tables] (表) をクリックします。Mobile Center では ID と表に Azure プラットフォームを使うため、[Connect Subscription] (サブスクリプションの接続) ボタンを使って Azure サブスクリプションに接続するよう求められます。サブスクリプションの接続が完了したら、[Create Table] (表の作成) をクリックできるようになります。この時点で、Visual Studio Mobile Center は Azure Mobile Apps サービスに新しいモバイル アプリ バックエンドとアプリ エンドポイントを作成します。https://mobile-{your-app-id}.azurewebsites.net/ (英語) でエンドポイント フォームを参照してください。表示されるポップアップで、新しい表の名前「Book」を入力します。次に、[Authenticated] (認証済み)、[Soft delete] (論理削除)、[Per-user data] (ユーザーごとのデータ) の各チェック ボックスをオンにし、[Dynamic schema] (動的スキーマ) チェック ボックスをオフにします。各オプションを簡単に説明します。

  • [Authenticated] (認証済み) は、表へのアクセスを認証済みユーザーのみに限定します。このオプションをオンにしないと、匿名アクセスが許可されます。
  • [Soft delete] (論理削除) は、レコードをデータベースから削除するのではなく、レコードを削除済みとマークできるようにします。これにより、レコードの削除を取り消すオプションが可能になります。[Queries] (クエリ) は、アクティブなレコードのみを返すようにフィルターをかけることができます。
  • [Dynamic schema] (動的スキーマ) は、新しいオブジェクトが挿入されたときにサーバーではなくクライアントに新しい列を動的に作成できるようにします。これは開発段階では便利ですが、運用環境で使うとセキュリティ上の問題が生じるため、アプリを運用環境に移行したら使用しないようにします。
  • [Per-user data] (ユーザーごとのデータ) は、表にユーザー列を追加して、現在のユーザー情報に基づいてデータにフィルターをかけられるようにします。このオプションは、認証が有効になっている場合に意味があります。

[Create] (作成) をクリックすると、Mobile Center によって多数のシステム列を含む表が生成されます。この表は、[Show system columns] (システム列の表示) スイッチ コントロールを選択するか、[Edit Schema] (スキーマの編集) をクリックして列を追加したときに表示されます (図 2 参照)。

システム列を含む新しい表のスキーマ
図 2 システム列を含む新しい表のスキーマ

列には、 文字列型、日付型、数値型、ブール型、バージョン型の 5 つの異なるデータ型を指定できます。実際には、バージョン型はバージョン列での内部使用のみを目的としています。これらの型は非常に柔軟で、プラットフォーム固有のさまざまなデータ型を受け取ることができます。たとえば、Microsoft .NET Framework では、Int32 型と倍精度浮動小数点型のオブジェクトを数値型の列に格納できます。このことは、サポート対象の他のプラットフォームにも当てはまります。覚えておきたいのは、日付には DateTime よりも DateTimeOffset を使用する方が都合がよいことです。DateTimeOffsetに はタイム ゾーン情報が含まれ、考慮されるのに対し、DateTime では考慮されません。ここで、[Add Column] (列の追加) をクリックし、 [Title] (タイトル) と [Author] (著者) という 2 つのシンプルな文字列型の列を追加します。ポップアップが表示され、列名とデータ型を入力できるようになります。目的の列を追加したら、追加手順として、列のアクセス許可を設定する必要があります。これを行うには、オプション ボタン (縦に 3 つのドットが並んでいるアイコン) を使います。このボタンには、コマンドをいくつか含むメニューが用意されています。その中から、[Change Permissions] (アクセス許可の変更) コマンドを使うと、データに対する操作ごとにアクセス許可を個別に指定できます (図 3 参照)。

表のアクセス許可の指定
図 3 表のアクセス許可の指定

準備ができたら [Save] (保存) をクリックします。ここで、オプション メニューを使うと、.csv ファイルのデータのアップロードや、表内のデータのクリア、表の削除を行うことができます。もう 1 つ、表ページのグリッド内に格納済みのデータを表示する機能も非常に便利です。

認証のセットアップ

次の手順では、認証をセットアップします。Mobile Center で、ページの左側にあるツール バーの [Identity] (ID) ボタンをクリックします。Azure Active Directory (Azure AD) の認証エンドポイントと、利用できる認証プロバイダー (Azure Active Directory、Microsoft Account、Facebook、Google、Twitter) の一覧が表示されます。当然複数の認証サービスを選択してもかまいませんが、今回の例では、Microsoft Account サービスを使います。どの認証サービスをクリックした場合でも、各プロバイダーのドキュメントへのリンクと、選択したプロバイダーに基づいて構成する必要のあるフィールドの一覧がポップアップに表示されます。Microsoft Account サービスの場合、ドキュメント (bit.ly/2peCBgf、英語) には、アプリを登録する方法と、アプリ ID とアプリ クライアント シークレットを取得する方法が記載されています。その手順は次のとおりです。

  1. Microsoft アカウント開発者ポータルを開きます。このポータルは apps.dev.microsoft.com にあります。ポータルには、Microsoft アカウントに関連付けられたアプリ (存在する場合) の一覧が表示されます。
  2. [Add an App] (アプリの追加) をクリックします。アプリ名を指定するよう求められます。アプリ名には特殊文字を含めないようにします。今回の例では、「MyBookshelf」と入力します。次に、[Create] (作成) をクリックします。
  3. ID とクライアント シークレットが生成されます。新しいアプリを追加すると、開発者ポータルでは、アプリケーション ID が生成され、アプリケーション ページに表示されます (図 4 参照)。クライアント シークレットも必要なので、[Generate New Password] (新しいパスワードを生成) をクリックして取得します。ポップアップにクライアント シークレットが表示されます。明示されるのはこのときだけなので、後で使用できるように安全な場所にコピーします。
  4. リダイレクト URI を指定します。リダイレクト URI は、ユーザーが資格情報を指定後に表示するページを認証サービスに指示します。これを行うには、[Add Platform] (プラットフォームの追加) をクリックし、[Web] をクリックします。[Redirect URIs] (リダイレクト URI) ボックスに、「https://mobile-{your-app-id}.azurewebsites.net/.auth/login/­microsoftaccount/callback」という形式で適切なリダイレクト URI を入力します。図 5 にこの手順を示します。

変更を保存し、Mobile Center に戻ります。次に、アプリの構成ページにクライアント ID とクライアント シークレットを追加します (図 6 参照)。

Microsoft 開発者ポータルでのアプリケーションの登録
図 4 Microsoft 開発者ポータルでのアプリケーションの登録

リダイレクト URI の入力
図 5 リダイレクト URI の入力

Microsoft Account Authentication サービスの構成
図 6 Microsoft Account Authentication サービスの構成

[Scope] (スコープ) で追加のアクセス許可を指定できますが、今回は該当しないので [Save] (保存) をクリックします。いくつか手順を実行するだけで、アプリの認証を正しく構成できます。他の認証プロバイダーでも同様です。ここで、クロスプラットフォーム アプリを作成します。そのため、なんらかのコードを記述します。

Xamarin サンプル プロジェクトの作成とセットアップ

Visual Studio 2017 で、[ファイル]、[新規作成]、[プロジェクト] の順に選択します。[Visual C#] の [Cross-Platform] ノードを見つけて、[クロスプラットフォーム アプリ (Xamarin.Forms またはネイティブ)] というプロジェクト テンプレートを選択します。MyBookshelf プロジェクトを呼び出し、[OK] をクリックします。[New Cross Platform App] (クロスプラットフォーム アプリの新規作成) ダイアログで、[空のアプリ] テンプレートを選択し、[UI テクノロジ] で [Xamarin.Forms] を、[コード共有方法] で [ポータブル クラス ライブラリ (PCL)]選択してから、[OK] をクリックします。Visual Studio Mobile Center サービス (Mobile Center SDK を含む) に対して機能させるには、次の NuGet パッケージをダウンロードしてインストールする必要があります。

  • Microsoft.Azure.Mobile.Crashes: アプリが Mobile Center とクラッシュ情報を共有できるようにします。Microsoft.Azure.Mobile パッケージとの依存関係があるため、このパッケージもインストールされます。
  • Microsoft.Azure.Mobile.Analytics: アプリが Mobile Center と使用状況情報を共有できるようにします。また、同じように Microsoft.Azure.Mobile との依存関係があります。
  • Microsoft.Azure.Mobile.Client: Azure Mobile Client SDK をインストールして、Windows アプリまたは Xamarin アプリが Azure Mobile Apps サービスと連携できるようにします。

次の手順ではオブジェクトをモデル化して、バックエンド サービスで表をマップします。

データ モデルの定義

コードを再利用しやすくするため、表の基本構造をマップする基底クラスを作成してから、特定の列を使って基底オブジェクトを拡張する派生クラスを作成します。基底クラスは INotifyPropertyChanged インターフェイスを実装し、UI にデータをバインドして、変更通知を発生させることも必要になります。ただし、今回は PCL プロジェクトに Model というフォルダーと、TableBase.cs および Book.cs という 2 つのコード ファイルを追加します。図 7 は、両方のクラス定義の全コードを示しています。

図 7 データ モデルの定義

// Requires the following directives:
// using System.ComponentModel and System.Runtime.CompilerServices
public abstract class TableBase : INotifyPropertyChanged
{
  private string id;
  public string Id
    {
      get
      {
        return id;
      }
      set
      {
        id = value; OnPropertyChanged();
      }
    }
    private string userId;
    public string UserId
    {
      get
      {
        return userId;
      }
      set
      {
        userId = value; OnPropertyChanged();
      }
    }
    private DateTimeOffset createdAt;
    public DateTimeOffset CreatedAt
    {
      get
      {
        return createdAt;
      }
      set
      {
        createdAt = value; OnPropertyChanged();
      }
    }
    private DateTimeOffset updatedAt;
    public DateTimeOffset UpdatedAt
    {
      get
      {
        return updatedAt;
      }
      set
      {
        updatedAt = value; OnPropertyChanged();
      }
    }
    private string version;
    public string Version
    {
      get
      {
        return version;
      }
      set
      {
        version = value; OnPropertyChanged();
      }
    }
    private bool deleted;
    public bool Deleted
    {
      get
      {
        return deleted;
      }
      set
      {
        deleted = value; OnPropertyChanged();
      }
    }
    public TableBase()
    {
      this.CreatedAt = DateTimeOffset.Now;
      this.UpdatedAt = DateTimeOffset.Now;
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
      PropertyChanged?.Invoke(this,
        new PropertyChangedEventArgs(propertyName));
    }
}
public class Book: TableBase
{
    private string author;
    public string Author
    {
      get
      {
        return author;
      }
      set
      {
        author = value; OnPropertyChanged();
      }
    }
    private string title;
    public string Title
    {
      get
      {
        return title;
      }
      set
      {
        title = value; OnPropertyChanged();
      }
    }
}

この手法であれば、各クラスに同じ共通プロパティを繰り返し用意する必要がなく、継承を利用するだけになります。PCL プロジェクトで、Constants.cs というコード ファイルを追加します。このコード ファイルの内容は以下のとおりです。

public static class Constants
{
  public const string BaseUrl = "https://mobile-{your-app-id}.azurewebsites.net/";
}

この定数にバックエンド サービスの URL を含め、毎回 URL を手作業で記入するのではなく、この定数を使用します。

認証の実装

Azure Mobile Client SDK を使うと、ユーザー認証が非常に簡単になります。実際必要なのは、MobileServiceClient.LoginAsync メソッドを呼び出すことだけです。LoginAsync は 2 つの引数を受け取ります。1 つは認証 UI に表示しなければならないコンテキスト、もう 1 つは MobileServiceAuthentication­Provider 列挙値による認証プロバイダーです。LoginAsync は、認証済みユーザーについての情報を含む MobileService­User 型のオブジェクトを返します。Xamarin.Forms では、iOS と Android が管理する UI コンテキストが異なるため、ユーザー認証のコードを PCL で共有できません。この問題は依存サービス パターンを使うことで解決できます。そのために、PCL に抽象ログイン メソッド定義を提供するインターフェイスと、そのインターフェイスのプラットフォーム固有の実装を追加します。PCL プロジェクトで、Authentication という新しいフォルダーと、以下のような IAuthentication.cs というインターフェイスを追加します。

using Microsoft.WindowsAzure.MobileServices;
using System.Threading.Tasks;
namespace MyBookshelf.Authentication
{
  public interface IAuthentication
  {
    Task<MobileServiceUser> LoginAsync(MobileServiceClient client,
      MobileServiceAuthenticationProvider provider);
    }
}

この LoginAsync のカスタム定義は、ビュー モデルから渡され、プラットフォーム固有のプロジェクトから LoginAsync メソッドを呼び出すために使われる MobileServiceClient クラスのインスタンスを受け取ります。Authentication.cs というファイルを Android プロジェクトと iOS プロジェクトの両方に追加してから、図 8図 9 を参照してください。これらの図には、Android と iOS それぞれの実装を示しています。

図 8 Android の Authentication.cs

using System;
using MyBookshelf.Authentication;
using Microsoft.WindowsAzure.MobileServices;
using Xamarin.Forms;
using System.Threading.Tasks;
using MyBookshelf.Droid;
[assembly: Dependency(typeof(Authentication))]
namespace MyBookshelf.Droid
{
  public class Authentication : IAuthentication
  {
    public async Task<MobileServiceUser> LoginAsync(MobileServiceClient client,
      MobileServiceAuthenticationProvider provider)
    {
      try
      {
        var user = await client.LoginAsync(Forms.Context, provider);
        return user;
      }
      catch (Exception)
      {
        return null;
      }
    }
  }
}

図 9 iOS の Authentication.cs

using Microsoft.WindowsAzure.MobileServices;
using MyBookshelf.Authentication;
using MyBookshelf.iOS;
using System;
using System.Threading.Tasks;
[assembly: Xamarin.Forms.Dependency(typeof(Authentication))]
namespace MyBookshelf.iOS
{
  public class Authentication : IAuthentication
  {
    public async Task<MobileServiceUser> LoginAsync(MobileServiceClient client,
      MobileServiceAuthenticationProvider provider)
    {
      try
      {
        // Attempt to find root view controller to present authentication page
        var window = UIKit.UIApplication.SharedApplication.KeyWindow;
        var root = window.RootViewController;
        if (root != null)
        {
          var current = root;
          while (current.PresentedViewController != null)
          {
            current = current.PresentedViewController;
          }
          // Login and save user status
          var user = await client.LoginAsync(current, provider);
          return user;
        }
        return null;
      }
      catch (Exception)
      {
        return null;
      }
    }
  }
}

この手法であれば、適切な実行コンテキストを渡して、プラットフォーム固有の各プロジェクトから LoginAsync を呼び出すことができます。

Azure Mobile Client SDK によるデータ アクセスの実装

MobileServiceClient クラスでは、表内のレコードの操作に必要なすべてのものが提供されます。最初に GetTable メソッドで表への参照を取得してから、ToEnumerableAync、InsertAsync、UpdateAsync、DeleteAsync などのメソッドを使ってそれぞれレコードをクエリ、挿入、更新、削除します。これらはすべてジェネリック メソッドなので、TableBase から派生するオブジェクトの操作に再利用できるデータ アクセス層を作成できます。ただし、PCL プロジェクトでは、DataAccess フォルダーと DataManager.cs というファイルが内部で追加されます。DataManager クラスを作成する前に、App.xaml.cs ファイルに以下のコードを追加して、DataManager 型の変数をアプリ レベルで利用できるようにします。

internal static DataManager DataManager;
public App()
{
  InitializeComponent();                      
  DataManager = new DataManager(Constants.BaseUrl);
  MainPage = new MyBookshelf.MainPage();
}

図 10 に、DataManager クラスのコードを示します。

図 10 データ アクセス層の実装

using Microsoft.WindowsAzure.MobileServices;
using MyBookshelf.Model;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace MyBookshelf.DataAccess
{
  public class DataManager
  {
    public MobileServiceClient Client { get; set; }
    public DataManager(string serviceUrl)
    {
      Client = new MobileServiceClient(serviceUrl);
    }
    public async Task SaveAsync<T>(IEnumerable<T> items) where T : TableBase
    {
      var table = this.Client.GetTable<T>();
      foreach (T item in items)
      {
        if (item.Id == null)
        {
          item.Id = Guid.NewGuid().ToString("N");
          await table.InsertAsync(item);
        }
        else
        {
          await table.UpdateAsync(item);
        }
    }
  }
    public async Task<IEnumerable<T>> LoadAsync<T>(string userId)
      where T : TableBase
    {
      var table = this.Client.GetTable<T>();
      var query = await table.Where(t => t.UserId == userId).ToEnumerableAsync();
      return query;
    }
  }
}

SaveAsync メソッドでは、Id プロパティを使って、項目が新規か既存かを検出します。項目が新規の場合、新しい GUID を生成し、その項目を挿入します。既存の場合はその項目を更新します。LoadAsync メソッドでは、UserId プロパティを使って、現ユーザーに基づいて項目の一覧をフィルター処理します。これを可能にするのはジェネリックとジェネリック定数で、どちらの手法も TableBase から派生するオブジェクトを操作します。

ビューモデル

ビューモデル クラスは、書籍のコレクション、Book 項目の操作に使えるコマンド、ログインのロジックを公開します。PCL プロジェクトで BookViewModel.cs という新しいファイルを ViewModel というサブフォルダーに追加してから、図 11 に示すコードを作成します。

図 11 ビューモデルの公開

using Microsoft.WindowsAzure.MobileServices;
using MyBookshelf.Authentication;
using MyBookshelf.Model;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace MyBookshelf.ViewModel
{
  public class BookViewModel : INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    private bool isBusy;
    public bool IsBusy
    {
      get
      {
        return isBusy;
      }
      set
      {
        isBusy = value; OnPropertyChanged();
      }
    }
    private bool isUserAuthenticated;
    public bool IsUserAuthenticated
    {
      get
      {
        return isUserAuthenticated;
      }
      set
      {
        isUserAuthenticated = value; OnPropertyChanged();
      }
    }
    private string userId;
    public string UserId
    {
      get
      {
        return userId;
      }
      set
      {
        userId = value; OnPropertyChanged();
      }
    }
    private ObservableCollection<Book> books;
    public ObservableCollection<Book> Books
    {
      get
      {
        return books;
      }
      set
      {
        books = value; OnPropertyChanged();
      }
    }
    private Book selectedBook;
    public Book SelectedBook
    {
      get
      {
        return selectedBook;
      }
      set
      {
        selectedBook = value; OnPropertyChanged();
      }
    }
    public BookViewModel()
    {
      this.Books = new ObservableCollection<Book>();
      this.IsBusy = false;
    }
    public Command SaveBooks
    {
      get
      {
        return new Command(async () =>
        {
          if (IsUserAuthenticated)
          {
            this.IsBusy = true;
            await App.DataManager.SaveAsync(this.Books);
            this.IsBusy = false;
          }
      });
      }
    }
    public Command LoadBooks
    {
      get
      {
        return new Command(async () =>
        {
          if (IsUserAuthenticated)
          {
            this.IsBusy = true;
            var listOfBooks = await App.DataManager.LoadAsync<Book>(UserId);
            this.Books = new ObservableCollection<Book>(listOfBooks);
            this.IsBusy = false;
          }
        });
      }
    }
    public Command AddNewBook
    {
      get
      {
        return new Command(() =>
          this.Books.Add(new Book { UserId = this.UserId }));
      }
    }
    public async Task LoginAsync()
    {
      var authenticator = DependencyService.Get<IAuthentication>();
      var user = await authenticator.LoginAsync(App.DataManager.Client,
        MobileServiceAuthenticationProvider.MicrosoftAccount);
      if (user == null)
      {
        IsUserAuthenticated = false;
        return;
      }
      else
      {
        UserId = user.UserId;
        IsUserAuthenticated = true;
        return;
      }
    }
  }
}

LoginAsync メソッドが IAuthentication インターフェイスのプラットフォーム固有の実装を DependencyService.Get メソッドを使って呼び出し、MobileServiceClient クラスのアクティブなインスタンスと現在の認証プロバイダーを渡しているのがわかります。

UI

サンプル アプリケーションの UI はとてもシンプルです。ListView を ViewModel のインスタンスにデータバインドする場合、Activity­Indicator はアプリがビジー状態のときに進行状況インジケーターを表示します。そのため、ViewModel でボタンをいくつかコマンドにデータバインドします。UI の XAML を図 12 に示します。次は MainPage.xaml ファイルです。

図 12 メイン ページの UI

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
  xmlns:x="https://schemas.microsoft.com/winfx/2009/xaml"
  xmlns:local="clr-namespace:MyBookshelf"
  x:Class="MyBookshelf.MainPage">
  <Grid BindingContext="{Binding}">
    <Grid.RowDefinitions>
      <RowDefinition Height="40"/>
      <RowDefinition Height="30"/>
      <RowDefinition />
      <RowDefinition Height="40" />
    </Grid.RowDefinitions>
    <Label Text="My Bookshelf" FontSize="Large" Margin="5"/>
    <ActivityIndicator x:Name="Indicator1" IsRunning="{Binding IsBusy}"
      IsVisible="{Binding IsBusy}" Grid.Row="1"/>
    <ListView HasUnevenRows="True" ItemsSource="{Binding Books}"
      x:Name="BooksListView"
      Grid.Row="2" SelectedItem="{Binding SelectedBook}" >
        <ListView.ItemTemplate>
          <DataTemplate>
            <ViewCell>
              <ViewCell.View>
               <Frame OutlineColor="Blue">
                 <Grid>
                    <Grid.RowDefinitions>
                      <RowDefinition/>
                      <RowDefinition/>
                    </Grid.RowDefinitions>
                    <Entry Placeholder="Title" Text="{Binding Title}"/>
                    <Entry Placeholder="Author" Text="{Binding Author}"
                  Grid.Row="1"/>
                 </Grid>
               </Frame>
              </ViewCell.View>
            </ViewCell>
          </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
   <StackLayout Grid.Row="3" Orientation="Horizontal"
     BindingContext="{Binding}">
     <Button Text="Load" x:Name="LoadButton" Command="{Binding LoadBooks}"/>
     <Button Text="Save" x:Name="SaveButton" Command="{Binding SaveBooks}"/>
     <Button Text="Add" x:Name="AddButton" Command="{Binding AddNewBook}"/>
   </StackLayout>
  </Grid>
</ContentPage>

分離コードでは、ページのバインディング コンテキストに ViewModel のインスタンスを割り当てる必要があり、ユーザーがページを開くたびにログインが必要であることをチェックする必要があります。コードは次のようになります。

private BookViewModel ViewModel { get; set; }
public MainPage()
{
  InitializeComponent();
  this.ViewModel = new BookViewModel();
  this.BindingContext = this.ViewModel;
}
protected async override void OnAppearing()
{
  base.OnAppearing();
  if (this.ViewModel.IsUserAuthenticated == false) await this.ViewModel.LoginAsync();
}

LoginAsync は OnAppearing メソッド内で呼び出します。これは、ページの初期化時と、ページが表示されるたびに非同期メソッドを呼び出せるようにするためです。

分析レポートとクラッシュ レポート向けのアプリの構成

1 行のコードで Xamarin.Forms アプリを構成して使用状況とクラッシュのレポートを Visual Studio Mobile Center に送信できます。App.xaml.cs で、以下のように OnStart メソッドをオーバーライドします。

// Requires using directives for Microsoft.Azure.Mobile,
// Microsoft.Azure.Mobile.Analytics and Microsoft.Azure.Mobile.Crashes
protected override void OnStart()
{
  MobileCenter.Start("android={Your Android App secret here};" +
    "ios={Your iOS App secret here}",
    typeof(Analytics), typeof(Crashes));
}

アプリ シークレットを指定することで、Android プロジェクトと iOS プロジェクトの両方を有効にできます。アプリ シークレットは、Mobile Center の [Getting Started] (はじめに) ページにあります。すべてのレポートは、Mobile Center の [Analytics] (分析) ページと [Crashes] (クラッシュ) ページにあります。

アプリケーションのテスト

ここでサンプル アプリを実行すると、最初に Microsoft アカウントのログイン画面が表示されます。認証を受けたら、書籍の一覧を表示、編集、保存できるようになります (図 13 参照)。

Android で実行中のサンプル アプリ
図 13 Android で実行中のサンプル アプリ

もちろん、iOS デバイスでも同様の結果が表示されます。いくつか項目を追加し保存してから Visual Studio Mobile Center の表ページに移動すると、レコードを表示するグリッドを確認できます。コードをさらに改善するには、Azure Mobile Client SDK とのオフライン同期と、ユーザーが認証されない場合の具体的なエラー処理を実装します。

まとめ

Visual Studio Mobile Center によって、モバイル アプリのバックエンド サービス (認証や表など) を実装する方法が飛躍的に簡素化されます。このような簡素化は、便利な UI を備えることで実現されるだけでなく、開発者に代わって、Azure Mobile Apps サービスをサポートする多くのインフラストラクチャをセットアップすることでも実現されます。Mobile Center に絶えずアクセスし、新しい機能の有無を確認してください。


Alessandro Del Sole は 2008 年から Microsoft MVP の一員です。彼は年間 MVP を 5 度受賞し、Visual Studio による .NET 開発に関する、書籍、電子ブック、説明ビデオ、記事を手がけてきました。彼は主に .NET およびモバイル アプリの開発、教育、コンサルティングに取り組む、シニア .NET 開発者として働いています。Twitter は、@progalex (英語) からフォローできます。

この記事のレビューに協力してくれた技術スタッフの Adrian Hall に心より感謝いたします。
Adrian Hall は、Azure Mobile Apps と、Mobile Center のモバイル バックエンド機能のプリンシパル プロダクト マネージャーです。  カンファレンスで頻繁に講演も行っており、『Develop Cloud Connected Mobile Apps with Xamarin and Microsoft Azure (Xamarin と Microsoft Azure を使ったクラウド接続型モバイル アプリの開発)』 (https://aka.ms/zumobook、英語) の著者でもあり、Azure Mobile Apps に関するブログや数本のビデオを公開しています。