前回はコーディングの前の準備として、Facebook SDK3.0のダウンロード、Facebook App作成などについて説明しました。
今回は実際にアンドロイドアプリからFacebookログインする部分をコーディングしていきます。
前編の「アンドロイドアプリからFacebookeへログインする方法(前編)」も参照しながら、読んでください。
一番簡単な実装は、Facebook SDKに含まれているButtonウィジェット(com.facebook.widget.LoginButton)や認証ダイアログ(com.facebook.widget.UserSettingsFragment)を利用することだと思います。
しかし、Buttonウィジェットを使うと、ボタンのデザインに自由度が欠けるということ、また、このボタンを使わないサンプルのコードでは、パーミッションの設定方法がよくわからなかったので、独自に実装してみました。
ここではemail取得のパーミッションを付加して、ログインしたユーザーのユーザー情報をログに出力することにします。アプリにログインするときはemailアドレスがよく使われるので、emailが取得できるサンプルになっています。
変数の宣言
メインのアクティビティに必要なメンバ変数を宣言します。
// ログインボタン private Button mFbloginBtn; // ライフサイクルヘルパー private UiLifecycleHelper mUiHelper; // セッションステートコールバックメソッド private Session.StatusCallback mFacebookCallback = new Session.StatusCallback() { @Override public void call(Session session, SessionState state, Exception exception) { onSessionStateChange(session, state, exception); } };
ライフサイクルヘルパーとはアクティビティのライフサイクルにあわせて、必要なセッション処理を実行します。アクティビティのライフサイクルハンドラーにあわせてコールする必要があります。セッションコールバックメソッドは、セッションの状態が変化したときに呼び出しされるメソッドです。
初期処理
このメソッドをonCreateでコールしておきます。
private void initFacebook(Bundle savedInstanceState) { // ライフサイクルヘルパーの初期化 mUiHelper = new UiLifecycleHelper(this, mFacebookCallback); mUiHelper.onCreate(savedInstanceState); // ログインボタンの初期化 mFbloginBtn = (Button)findViewById(R.id.buttonAuth); mFbloginBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { loginFacebook(); } }); }
ログイン・ログアウト
今回は、ログアウトは使用していませんが、ログイン済みならログアウトボタンを表示するようにします。
ログイン処理では、リクエストを生成し、パーミッションを付加して、セッションとともに認証要求します。
private void loginFacebook() { // リクエストの生成 OpenRequest openRequest = new OpenRequest(this).setCallback(mFacebookCallback); // emailを要求するパーミッションを設定 openRequest.setPermissions(Arrays.asList("email")); // セッションを生成 Session session = new Builder(this).build(); // アクティブセッションとする。 Session.setActiveSession(session); // 認証を要求する。 session.openForRead(openRequest); return session; } private void logoutFacebook() { Session session = Session.getActiveSession(); if (!session.isClosed()) { // セッションとトークン情報を廃棄する。 session.closeAndClearTokenInformation(); } }
セッションステートコールバック
認証から戻ってきたときの処理を記述します。ここでは認証が成功すれば、さらにログインした人の情報を取得するためにGraphAPIを呼び出しています。HTTP通信が必要なので非同期処理になっています。
SDK3.5では、executeMeRequestAsyncがdeprecatedされましたので、3.5.2でのコーディングを追記します(2013/11/10)。
SDK3.0
private void onSessionStateChange(Session session, SessionState state, Exception exception) { if (session.isOpened()) { // GraphAPIのmeリクエストを呼び出す。 Request.executeMeRequestAsync(session, new FacebookGraphUserCallback("wait...") { @Override public void onCompleted(GraphUser user, Response response) { super.onCompleted(user, response); Log.d(TAG, "user = " + user.getInnerJSONObject()); } }); } }
SDK3.5.2
private void onSessionStateChange(Session session, SessionState state, Exception exception) { if (session.isOpened()) { // GraphAPIのmeリクエストを呼び出す。 Request.newMeRequest(session, new FacebookGraphUserCallback("wait...") { @Override public void onCompleted(GraphUser user, Response response) { super.onCompleted(user, response); Log.d(TAG, "user = " + user.getInnerJSONObject()); } }).executeAsync(); } }
ライフサイクルメソッド
以下のライフサイクルメソッドをOverrideして、それぞれFacebookのライフサイクルヘルパーのメソッドを呼び出しておきます。
@Override public void onPause() { super.onPause(); mUiHelper.onPause(); } @Override public void onDestroy() { super.onDestroy(); mUiHelper.onDestroy(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); mUiHelper.onActivityResult(requestCode, resultCode, data); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mUiHelper.onSaveInstanceState(outState); }
グラフユーザーコールバック
認証が得られたログインユーザーの情報を取得するときにプログレスを表示するためのコールバッククラスです。
class FacebookGraphUserCallback implements Request.GraphUserCallback { private ProgressDialog mProgress = null; public FacebookGraphUserCallback(String message) { mProgress = new ProgressDialog(MainActivity.this); mProgress.setMessage(message); mProgress.setProgressStyle(ProgressDialog.STYLE_SPINNER); mProgress.show(); } @Override public void onCompleted(GraphUser user, Response response) { mProgress.dismiss(); } }
サンプルの実行
このプログラムは以下のように動作します。まず、ログイン画面を表示します。
ログインボタンをタップすると、Facebookの認証画面へ遷移し、Facebookアカウントの入力が求められます。アカウントを入力してログインボタンをタップします。
最後にどのような情報を要求しているかの説明と、許可を求めます。よければOKボタンをタップすると、元の画面へ戻ります。
このとき、ログにJSON形式のユーザー情報が表示されます。個人情報は伏せさせていただいています。メールアドレスも取得できています。
{ "location":{ "id":"xxx", "name":"Osaka-shi, Osaka, Japan" }, "locale":"ja_JP", "link":"http:\/\/www.facebook.com\/xxx", "updated_time":"2013-0407T08:37:27+0000", "id":"xx53xx04xx", "first_name":"xxx", "timezone":9, "username":"xxx", "quotes":"xxx", "email":"hoge@hoge.com", "verified":true, "name":"xxx", "last_name":"xxx", "gender":"male" }
これでFacebook SDK3.0でアンドロイドアプリからFacebookログインにできました。
SDK2.0でFacebookクラスに集約されていた機能が、SDK3.0では、Session,Request,UiLifecycleHelperの各クラスに機能分割されたようです。
認証アクティビティを行き来するアプリでは、アクティビティで遷移するより、ひとつのアクティビティで複数のFragmentを制御する方が実装が簡単でしょう。特に戻るボタンを押されたときの処理を考えると、このような実装がよいのではないでしょうか。実際、Facebookのサンプルでも、そのような実装があります。
蛇足ですが、com.facebook.widget.LoginButtonでは、com.facebook.internal下のAPIが結構利用されています。
これらを参考にしようと思いましたが、com.facebook.internal下のクラスは、いつ変更が加えられたり、deprecatedされるかわからないらしいので、あまり使わない方がよさそうです。