Android SDKのSampleSyncAdapterの使い方

Androidのアプリケーションの真髄はクラウドと連携する機能だと思う。認証機能であったり、データの同期機能であったり。そういった意味ではSDKのサンプル、SampleSyncAdapterは初心者としては読破しておかなければならないプログラムだろう。ところが、“Account Managerについて”にも書いたが、SampleSyncAdapterは初心者には解り難い。認証や同期、サービスやプロバイダが絡み合っているアプリケーションである、と言う事もある。しかし何よりデバイスにインストールしても何のアクティビティも起動してくれない、というのが初心者には分かり辛いところだろう。私はこのアプリケーションをどうやって利用するのか中々解らなかった。しかし、“よく分からないから飛ばしちゃえ”という性格でもないのでネチネチと調べてみた。で、ようやく動かすことができた。

実際に、このサンプルをどの様に使うかはこの後にメモっておくが、まず、SampleSyncAdapterの構造についてチョットだけ触れておく。

SampleSyncAdapterって?

まず、SampleSyncAdapterはAndroidManifest.xmlを見ると2つのサービス(AuthenticationServiceとSyncService)と1つのアクティビティ、AuthenticatorActivityから構成されているが分かる。普通のアプリケーションであれば、起動するとメイン・アクティビティが画面に表示されるが、そのためにはactivityに次のインテント・フィルタが記述されていなければならない。

<intent-filter>
	<action android:name="android.intent.action.MAIN" />
	<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

しかし、このインテント・フィルタが記述されていないので、アプリケーションをインストールしてもAuthenticatorActivityは起動されないし、ランチャーにも表示されない。本来、インテント・フィルタが記述されている部分には、

<!--
    No intent-filter here! This activity is only ever launched by
    someone who explicitly knows the class name
-->

というコメントがある。つまり、このアクティビティは別のもの(someone)から起動されるということ。“別のもの”ってなに? この説明が書いていないので分からなかった。ちなみに、無理やりaction.MAINとcategory.LAUNCHERのインテント・フィルタを追加すると、アプリケーションの実行と同時にAuthenticatorActivity起動されるし、ランチャーにもアイコンが表示される。AuthenticatorActivityが起動すると画面にユーザ名とパスワードを入力するダイアログが表示される。

さて、調べていくと“別のもの”とはAccountManagerのようだ。AccountManagerはAndroid OSの基本的な機能の一つで、最初からOSに組み込まれている。では、AccountManagerはどうやって(何が原因で)AuthenticatorActivityを呼び出すのか? サンプルの中にAuthenticatorActivityとは別にAuthenticator.javaというクラスがあり、このクラスがAuthenticatorActivityを使ってユーザからGUI画面を使ってユーザ名とパスワードを入力するようにAccountManagerに依頼している。Authenticatorの幾つかのメソッドではAuthenticatorActivityを呼び出すためのインテントを作成して、それをBundleに梱包してAccountManagerに返している。なお、AuthenticatorはAccountManagerに対するプラグイン拡張モジュールである(“Account Managerについて”参照)。

つまり、まず認証を必要としているアプリケーションがある。それがAccountManagerを呼び出す。AccountManagerはアカウントのタイプに応じたAuthenticatorを呼び出す。Authenticatorでは実際の認証を行うが、認証の際にユーザ名が空だったりパスワードが指定されていなかったり、またはトークンの期限が切れているなど条件で再度ユーザからユーザ名とパスワードの入力が必要と判断した場合、“認証が成功した”という情報の代わりにAuthenticatorActivityを呼び出すインテントを作成してAccountManagerに返す。そこでAccountManagerはAuthenticatorActivityを呼び出す。と言うのが大まかな流れとなる。

それでは“認証を必要としているアプリケーション”とは? SampleSyncAdapterサインプルではSync Serviceとなっている。SyncAdapter.javaのonPerformSyncメソッドでAccountManagerのblockingGetAuthTokenメソッドを呼び出してる。つまり、クラウド上のデータと同期をとる時に(当たり前だか)認証している。では、SyncAdapterは誰に呼ばれるのか? SyncService.javaでサービスの本体としてSyncAdapterのインスタンスを作成し、他のアプリケーションからのバインドに対するリスナーとしてonBindを定義している。つまり、このonBindを通してSyncAdapterをサービスの機能として利用できるようになる(“AndroidのRemote Serviceについて”参照)。

では、最後に、誰がSync Serviceを呼び出すのか? これはイベントの発生よってAndroid OS自身が呼び出す(ACTION_AUTHENTICATOR_INTENTというインテントを使ってSyncServiceを起動する)。イベントとはユーザがGUIを使って明示的にデータの同期を要求したり、一定時間が経って自動的に同期をしたり、等などだろう。

以上で、データの同期に関わる認証のシステム構成が大体分かったのだか、サンプルSampleSyncAdapterを理解する上で、もう一つ知っておきたいことがある。何のデータを同期するのか? と、どこにあるデータを同期するのか? だ。マニフェストにもあるとおり、このサンプルで唯一GUIを持っているのがAuthenticatorActivityなのだが、これは単にユーザにユーザ名とパスワードを入力してもらうだけのものだ。では、同期したデータはどうやって観るのか?

このサンプルはAndroidに標準でついている“Contacts(連絡先)”アプリケーションと連携して使うようになっている。つまり、このサンプルのメインのGUIは“連絡先”だった。これが分からなくて1週間近くもマゴマゴしていた。そして、このアプリケーションが扱う(そしてクラウドと同期する)データは連絡先のデータだった。

このサンプルでは、同期する先は“http://samplesyncadapter.appspot.com/”というサイトを利用するようになっている。このサイトはサンプルの試験用に誰でもデータを登録することができる。(一方で、誰でも他人のデータを書き換えたり消去したりもできる。)このサイトはGoogle App Engineで実装されているようだ。サンプルのディレクトリに“samplesyncadapter_server”というサブディレクトリがあるが、ここにはApp Engineで使うPythonのプログラムが入っている。従って、App EngineのSDKをダウンロードして、このPythonのサンプルプログラム実行すれば、ローカル(http://localhost:8080)でもサーバのデモができる。

SampleSyncAdapterの使い方

まず、このサンプルをインストールしていない状態とした状態を比較するために、サンプルをインストールしない状態でMENUの[Settings(設定)]から設定メニューを出し、[Accounts & Sync(アカウントと同期)]を選択する。そして画面下にある[Add account(アカウントを追加)]ボタンを押す。するとアカウントのタイプ(種類)として“Corporate(コーポレート)”と“Google”の2つが表示されている。

一旦、ホームに戻して、サンプルプログラムをインストールする(Eclipseを使っているのであれば[run]ボタンをクリックする)。この状態ではデバイスには何の変化もない。そこで程と同様に[MENU]-[Settings(設定)]-[Accounts & Sync(アカウントと同期)]-[Add account(アカウントを追加)]と進むと次の様にアカウントのタイプとして“SamplesyncAdapter”が増えていることが確認できる。

さて、ここからアカウントを指定するのだが、その前にクラウド上にアカウントと連絡先のデータを作っておく必要がある。インターネット・ブラウザから“http://samplesyncadapter.appspot.com/users”をアクセスする。すると、現在この試験サイトの登録されている“連絡先”の一覧が出てくる。ページの一番下までスクロールする。

[Insert More]というリンクをクリックして自分専用の試験アカウント(連絡先データ)を作成する。世界中の人がこの試験サイトを使っているので、できるだけカブらないようなHandle名にする。

ここでは順次、次の3つのデータを登録してゆく:

  • myssatest1 Tanaka Minoru
  • myssatest2 Suzuki Sigeru
  • myssatest3 Satoh Kazuko

左側の“myssatest[1-3]”はHandle名でこれがSamplesyncAdapterではユーザ名となる。名前やStatus、電話番号は適当に入力する。データを入力したら[Submit]ボタンを押す。すると一覧のページ戻り、一番下までスクロールすると今入力したデータが登録されていることがわかる。(ただし、登録するとHandle名とは別に内部的なID(ユニークな番号)が自動的に割り当てられるので必ずしも“最後”にリストされているとは限らない。見当たらない場合はページ内検索をしてみる。)

同様にあと2名分のデータを登録する。



(割り振られる内部的なIDにより、必ずしも入力した順番に並ぶとは限らない。)
さて、ここでは“私”は“Tanaka Minoru”だとする。そこで“myssatest1”をユーザ名として使って認証できるようにパスワードを設定する。ブラウザに直接“http://samplesyncadapter.appspot.com/add_credentials”を指定すると、パスワード設定画面になる。任意のパスワードを入力して[Submit]をクリックする。

次に“私(Tanaka Minoru)”の友達として“Suzuki Sigeru"と“Satoh Kazuko”を登録する。“Minoru_Tanaka”の右側の[Friends]をクリックする。

[Add More]のリンクをクリックして友達を登録する。


“お友達”として登録したいHandle名を順次追加してゆく。

以上で、クラウド上のデータの準備は完了である。

バイスの設定に戻る。[MENU]-[Settings(設定)]-[Accounts & Sync(アカウントと同期)]-[Add account(アカウントを追加)]と進みリストされている[SamplesyncAdapter]をタッチする。するとAuthenticatorActivityのユーザ名&パスワード入力画面が出てくる。ここではユーザ名として“myssatest1”、パスワードとして“hirakegoma”を入力して[Sign in]をタッチする。

管理対象アカウントとして“myssatest1”が追加され、同期が“ON”になっていることを確認する。

ホーム画面に戻り、ランチャーからContacts(連絡)を起動する。

この例では、このデバイスにはまだ1件も連絡先を登録していないので、説明文が現れている(既に連絡先が登録されていても以下の操作は同じ)。[MENU]ボタンを押してメニューを表示して“Display options(表示オプション)”をタッチする。

すると“myssatest1”のデータを連絡先として表示するか指定するチェックボタン(“All Contacts”)があるのチェックをしてから[Done]にタッチする。すると、連絡先の画面に戻り、クラウド上で登録したデータが表示されていることが確認できる。



上の例ではLocale(言語)を日本語にしていないので電話番号の表示がちょっと変だが、Localeを“ja_JP”に設定すれば、ちゃんと表示される。

これでこのサンプルの挙動が分かるのでコードを追うのも楽になる。

なお、このサンプルプログラムはあくまでもサンプルであり実用レベルではない。そのため、デバイス側でデータを変更して、それでクラウド上のデータを更新する、ということは出来ない。クラウドからの一方通行になっている。従って同期の確認をするのであれば、ブラウザを使ってクラウド上のデータを変更して、それがデバイス側で更新されていることを確認することになる。