アプリ内からFacebookへ投稿する場合について。
Facebookから提供されているsample appを参照しながら処理を盛り込んでみたのですが、
うまくいなかい部分があり、少し手を加えたのでその備忘録です。
下記ページにFacebook SDKのインストールからプロジェクトの作成までの手順が載っています。
・Android用Facebook SDKスタートガイド
今回作成したのは、ログインボタンとメッセージ入力欄と投稿ボタンだけのシンプルな画面です。
今回は、SDKに同梱されていたサンプルプロジェクト(HelloFacebookSample)をベースに作成してみました。
写真の投稿は不要なので削除し、またログイン処理の部分でうまくいかなかった部分はログインのドキュメントを参考にしながら処理を変更しました。
ログイン処理には、Facebookから提供されているLoginButtonクラスを使用しています。
LoginButtonクラスはセッション状態を保持しているので、ログイン/ログアウトの表示は自動で切り替わります。
ユーザから基本的なpermissionしか求めない場合には、LoginButtonクラスを設置するだけで済みます。
今回は投稿するpermission(publish_actions)が必要となるため、投稿時にユーザに許可を求める処理を追加しました。
ログインダイアログは、Facebook公式アプリがインストールされている場合とインストールされていない場合の2種類あります。
Facebook公式アプリがインストールされている場合
Facebook公式アプリのログイン画面が表示されます。
Facebook公式アプリがインストールされていない場合
ログインダイアログがポップアップで表示されます。
初めてアプリからFacebookにアクセスする際には、ログイン時にアクセス許可を求めてきます。
Facebook公式アプリがインストールされていない場合
なぜか右側に黒い■が表示されているのですが、不明です。。。
初めてアプリからFacebookに投稿する際には、投稿許可を求めてきます。
layoutファイル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:facebook="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:background="@color/facebook_light_gray" android:orientation="vertical" tools:context=".FacebookPostActivity" > <com.facebook.widget.LoginButton android:id="@+id/login_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" facebook:confirm_logout="false" /> <EditText android:id="@+id/editText_post" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:gravity="top" android:padding="10dp" android:background="@drawable/shape_round_corner" android:inputType="textMultiLine" android:lines="15" android:textSize="12sp" android:visibility="invisible" > </EditText> <Button android:id="@+id/btn_post" style="?android:attr/buttonStyle" android:layout_marginTop="20dp" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:gravity="center" android:background="@drawable/shape_facebook_post_btn" android:text="@string/btn_post" android:textColor="@color/white" android:textSize="16sp" android:visibility="invisible" /> </LinearLayout> |
Facebook投稿Activity
アプリからFacebookにアクセスした後、
アプリからFacebookに再度ログインしようとしてもログインできないことがありました。
エラーログを見たところ、facebookのパスワードを変更したことが原因のようでした。
”loginButton onError:UnknownError: ApiException:Error validating access token: Session does not match current stored session. This may be because the user changed the password since the time the session was created or Facebook has changed the session for security reasons.”
Facebookのパスワードを変更した場合には、Facebook公式アプリにログイン中である場合には
一旦ログアウトしてから再度アプリからログインするとログインできました。
このような場合を考慮して、ログイン時にFacebookAuthorizationExceptionが発生した場合には
メッセージを表示するように処理を追加しました。(57行目)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
public class FacebookPostActivity extends Activity { private static final String TAG = "FacebookPostActivity"; private static final String FACEBOOK_PERMISSION_PUBLISH = "publish_actions"; private static final String PENDING_ACTION_BUNDLE_KEY = "com.example.facebookpost:PendingAction"; private enum PendingAction { NONE, POST_STATUS_UPDATE } private LoginButton loginButton; private EditText postText; private Button postBtn; private UiLifecycleHelper uiHelper; private PendingAction pendingAction = PendingAction.NONE; private Session.StatusCallback callback = new Session.StatusCallback() { @Override public void call(Session session, SessionState state, Exception exception) { onSessionStateChange(session, state, exception); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); uiHelper = new UiLifecycleHelper(this, callback); uiHelper.onCreate(savedInstanceState); if ( savedInstanceState != null ) { String name = savedInstanceState.getString(PENDING_ACTION_BUNDLE_KEY); pendingAction = PendingAction.valueOf(name); } setContentView(R.layout.activity_facebook_post); loginButton = (LoginButton)findViewById(R.id.login_button); loginButton.setOnErrorListener(new OnErrorListener() { @Override public void onError(FacebookException error) { Log.d(TAG, "loginButton onError():"+error.getMessage()); if ( error != null ) { if ( error instanceof FacebookOperationCanceledException ) { Log.d(TAG, "FacebookOperationCanceledException"); } else if ( error instanceof FacebookAuthorizationException ) { Log.d(TAG, "FacebookAuthorizationException"); new AlertDialog.Builder(FacebookPostActivity.this) .setMessage("ログイン処理でエラーが発生しました。\n公式facebookアプリにログインしている場合には、一旦ログアウトした後再度ログインしてください。") .setPositiveButton(R.string.ok, null) .show(); } else { Log.d(TAG, "other Exception"); } } } }); postText = (EditText)findViewById(R.id.editText_post); postBtn = (Button)findViewById(R.id.btn_post); postBtn.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { performPublish(PendingAction.POST_STATUS_UPDATE); } }); updateUI(); } @Override protected void onResume() { super.onResume(); uiHelper.onResume(); updateUI(); } @Override protected void onPause() { super.onPause(); uiHelper.onPause(); } @Override public void onDestroy() { super.onDestroy(); uiHelper.onDestroy(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); uiHelper.onActivityResult(requestCode, resultCode, data); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); uiHelper.onSaveInstanceState(outState); outState.putString(PENDING_ACTION_BUNDLE_KEY, pendingAction.name()); } /* セッション状態が変更になった時 */ private void onSessionStateChange(Session session, SessionState state, Exception exception) { if ( pendingAction != PendingAction.NONE && (exception instanceof FacebookOperationCanceledException || exception instanceof FacebookAuthorizationException) ) { Log.w(TAG, "error occured:" + exception.getMessage()); new AlertDialog.Builder(FacebookPostActivity.this) .setMessage(R.string.message_permission_not_granted) .setPositiveButton(R.string.ok, null) .show(); pendingAction = PendingAction.NONE; return; } else if ( state == SessionState.OPENED_TOKEN_UPDATED ) { handlePendingAction(); } updateUI(); } private void handlePendingAction() { PendingAction previouslyPendingAction = pendingAction; // These actions may re-set pendingAction if they are still pending, but we assume they // will succeed. pendingAction = PendingAction.NONE; if ( previouslyPendingAction == PendingAction.POST_STATUS_UPDATE ) { postStatusUpdate(); } } /* 投稿権限確認&取得 */ private void performPublish(PendingAction action) { Session session = Session.getActiveSession(); if ( session != null ) { pendingAction = action; if ( hasPublishPermission() ) { // We can do the action right away. handlePendingAction(); return; } else if ( session.isOpened() ) { // We need to get new permissions, then complete the action when we get called back. session.requestNewPublishPermissions(new Session.NewPermissionsRequest(this, FACEBOOK_PERMISSION_PUBLISH)); return; } } } /* 投稿権限有無返却 */ private boolean hasPublishPermission() { Session session = Session.getActiveSession(); return session != null && session.getPermissions().contains(FACEBOOK_PERMISSION_PUBLISH); } /* UI更新 */ private void updateUI() { Session session = Session.getActiveSession(); if ( session != null && session.isOpened() ) { Log.d(TAG, "session.isOpened"); postText.setVisibility(View.VISIBLE); postBtn.setVisibility(View.VISIBLE); } else { Log.d(TAG, "session.isClosed"); postText.setVisibility(View.INVISIBLE); postBtn.setVisibility(View.INVISIBLE); } } /* Facebookに投稿 */ private void postStatusUpdate() { if ( hasPublishPermission() ) { final String postMessage = postText.getText().toString(); Request request = Request.newStatusUpdateRequest(Session.getActiveSession(), postMessage, new Request.Callback() { @Override public void onCompleted(Response response) { showPublishResult(response.getGraphObject(), response.getError()); } }); request.executeAsync(); } else { pendingAction = PendingAction.POST_STATUS_UPDATE; } } /* 投稿結果表示 */ private void showPublishResult(GraphObject result, FacebookRequestError error) { if ( error == null ) { showToast("Facebookに投稿しました。"); finish(); } else { showToast("Facebookへの投稿に失敗しました。"); Log.d(TAG, "error:"+ error.getErrorMessage()); } } /* Toast表示 */ private void showToast(String text) { Toast.makeText(this, text, Toast.LENGTH_SHORT).show(); } } |