2011年9月28日水曜日

Android からApp EngineのフォームにPOSTする

「Google アカウントを使用して Google App Engine の認証を行う」の続きです。

Google App Engine のスタートガイドで作成しているゲストブックのフォームにポストするサンプルです。



以前のソースはActivityクラスにコードを記載してましたが、もう少し汎用的なクラスを作成しました。

GoogleServiceAuthenticator


  • コンストラクタにはContextを指定してます。
  • getGoogleAccounts() で、アカウントリストを取得できます。
  • execute()で、認証を実行してます。
    • 引数 accountには、リストから選ばられた一意のアカウントを指定します。typeは、Googleのアカウントタイプ(AppEngineの場合は"ah")。postExecuteCallbackには、認証終了後にコールしたいクラスを指定します。
    • AccountManagerのgetAuthTokenを呼び出します。
      • GetAuthTokenCallbackをcallbackに指定してます。
      • GetAuthTokenCallbackのrun()の認証処理の実態のgetAuthToken()を呼び出してます。
    • getAuthToken()では、認証処理を失敗時のリトライのためにループさせてます。
      • getLoginUrl()を呼び出して、アプリのUrlを作成。
        • https://yourappl.appspot.com/_ah/login?continue=http://localhost/&auth=[authToken]
        • authTokenは、AccountManagerから取得した文字列を指定してます。
      • urlを読んで、レスポンスを取得。
      • 取得したレスポンスが500の場合、AccountManagerのキャッシュからauthTokenを削除して、リトライをさせてます。
      • 認証に成功したら、Cookieから、ASCID または、SACSIDを取得します。
        • httpsで認証した場合は、SACSID、httpの場合は、ASCIDが取得できます。
    • その後、postExecuteCallbackを実行させてます。
      • postExecuteCallback内で、App Engineにアクセスするときに、Http Headerの CookieにASCID/SACSIDをセットする必要があります。


Activityの実装例

GoogleServiceAuthExampleActivity


フルプロジェクトはgithubに上げました。
http://github.com/granoeste/GoogleServiceAuthExample

Google アカウントを使用して Google App Engine の認証を行う

AccountManager から、端末に登録されているGoogleアカウントを取得して、
そのアカウントでGoogle App Engineの認証を行う簡単なサンプルです。


AndroidManifest.xmlは、次のパーミッションを指定します。

  • android.permission.GET_ACCOUNTS
  • android.permission.MANAGE_ACCOUNTS
  • android.permission.USE_CREDENTIALS




Activity


AccountManagerから、AccountsByTypeに"com.google"を指定して、Googleアカウントの一覧を取得します。
それをリスト表示してます。
※リストは簡易的に標準のレイアウトを使用してます。

public class AccountList extends ListActivity { protected AccountManager accountManager; protected Intent intent; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); accountManager = AccountManager.get(getApplicationContext()); Account[] accounts = accountManager.getAccountsByType("com.google"); this.setListAdapter(new ArrayAdapter( this, android.R.layout.simple_list_item_1, accounts)); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { Account account = (Account)getListView().getItemAtPosition(position); AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, "ah", null, this, null, null); Bundle authTokenBundle; try { authTokenBundle = accountManagerFuture.getResult(); String authToken = authTokenBundle.get( AccountManager.KEY_AUTHTOKEN).toString(); Log.i(TAG,"authToken:"+authToken); } catch (OperationCanceledException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (AuthenticatorException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
リストで選んだAccountでGoogle App Engineの認証を行ってます。
AccountManager#getAuthToken() の 第2引数に AuthTokenTypeを指定します。
"ah"がGoogle App EngineのAuthTokenTypeとなってます。

AuthTokenTypeについては、次のサイトが参考になると思います。
  Account Managerについて - adsaria mood
  Google Data APIs Frequently Asked Questions - Google Base Data API - Google Code

認証画面が表示されます。

ユーザがAllowを選択するとauthTokenを取得することができます。


2011年9月19日月曜日

外部メディア (SDカード) へのインストール不可にする


Android 2.2.x (Froyo) から、アプリケーションは内蔵ストレージ(携帯端末)だけでなく、外部メディア(SDカード) にインストールさせることが可能になってます。

端末によっては、内蔵ストレージは、通常数百MBとサイズが小さく、プリインストールのアプリケーションなどで、ユーザが使用できるサイズ100MB以下の場合があります。
その場合、ゲームなどサイズの大きいアプリケーションは、2GB-32GBとサイズの大きい外部メディアにインストールさせることで、内蔵ストレージの消費を抑えることができます。

しかし、常に常駐するタイプのものや、ホームに配置するウィジェットの場合、外部メディアにインストールされてしまうと問題が発生します。

外部メディアは、端末から取り外したり、USBでパソコンと接続した場合にアンマウントされてしまいます。アンマウントされてしまうと、端末から外部メディアが認識できなくなり、その上で動作していたアプリケーションも停止することなります。

この問題を防ぐために、アプリケーションの開発時に外部メディアに移動できないように設定することが可能です。


AndroidManifest.xmlの<manifest>タグに、android:installLocation属性を定義します。
"internalOnly"と定義することで、外部メディアへの移動が出来なくなります。

android:installLocation属性の詳細はDev Guideを参照してください。
<manifest> | Android Developers

android:installLocation属性には、他に"auto"と"preferExternal"が設定することが可能です。
auto - アプリケーションは、外部ストレージにインストールすることができますが、システムはデフォルトで内部ストレージにアプリケーションをインストールします。内部ストレージがいっぱいになっている場合、システムは外部ストレージにインストールします。
preferExternal - アプリケーションは、外部ストレージ(SDカード)にインストールされることを優先します。


Android 2.1.x (Eclar) までは、外部メディアへのインストールができないため、android:installLocation属性はありませんので、通常のインストール先は内蔵ストレージとなります。
Android 2.2.x (Froyo)でも、android:installLocation属性を設定していない場合、通常のインストール先は内蔵ストレージとなります。

通常の端末の状態では、問題はありませんが、アプリケーションの通常のインストール先を内蔵ストレージから外部ストレージに変更することが出来てしまいます。

USB接続して、次のコマンドを実行します。

adb shell pm setInstallLocation 2
コマンドを実行することで、アプリケーションの通常のインストール先を外部メディアに変更します。

このような場合、android:installLocation属性に"internalOnly"を指定してない場合、外部メディアにインストールされてしまうことになります。
ウィジェットの場合、外部メディアにインストールされると、ホーム画面でウィジェットの一覧に表示されなくなります。


なので、
ウィジェットや常駐アプリは android:installLocation属性に "internalOnly" を指定しましょう!!

Android 2.1 以下を対象とするアプリケーションの場合、プロジェクトのビルドターゲットにAndroid 2.2 以上を指定して、AndroidManifest.xmlにuses-sdkタグでターゲットバージョンを指定します。