(From official document page)"If the access token is available already assign it" ??!
Scenario
Due to the internal design of SDK, integration of Facebook Login may depend on you app structure. In this article, I'm going to show one of the scenarios.
- User would see a splash Activity(an entry Activity) right after launching the app.
- The splash Activity would check the login information.
- If the user had login, jump to the main Activity, otherwise, jump to the login/register Activity. (Of course, the main Activity would use Facebook APIs).
This login flow is slightly different from that in official documentation page, which seems to leverage Fragment. Also, I simply use the LoginButton widget from SDK.
(Note: Facebook SDK version here is v4.12.1. I skip the setup steps which, unlike the development documents, is written pretty well in the official tutorial.)
(Note: Facebook SDK version here is v4.12.1. I skip the setup steps which, unlike the development documents, is written pretty well in the official tutorial.)
Implementation
In the splash Activity(here we call "SplashActivity"), we have the following code snippet.
public class SplashActivity extends AppCompatActivity { private Intent mLoginIntent; private Intent mMainIntent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mMainIntent = new Intent(this, MainActivity.class); mLoginIntent = new Intent(this, LoginActivity.class); FacebookSdk.sdkInitialize(getApplicationContext(), new FacebookSdk.InitializeCallback() { @Override public void onInitialized() { checkFbLogin(AccessToken.getCurrentAccessToken()); } }); AppEventsLogger.activateApp(getApplication()); } private void checkFbLogin(AccessToken currentToken){ if(currentToken != null){ startActivity(mMainIntent); }else{ startActivity(mLoginIntent); } finish(); } }
FacebookSdk.sdkInitialize() must be called as early as you can. SplashActivity as previous mentioned, need to check the login information. Lots of people had complained that AccessToken.getCurrentAccessToken() didn't behave like the document said, which should return null if use hasn't login. The key is that the real "token loader" is FacebookSdk.sdkInitialize(), which is asynchronous, so you need to wait a little bit for the SDK initialization. Nevertheless, one should leverage the "on complete callback" of FacebookSdk.sdkInitialize() instead of pausing for a while by Thread.sleep() or Handler. Because the proper pausing interval may vary from device to device.
Here is the LoginActivity.
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(!FacebookSdk.isInitialized()){ FacebookSdk.sdkInitialize(getApplicationContext()); AppEventsLogger.activateApp(getApplication()); } setContentView(R.layout.activity_login); // Login button provided by SDK LoginButton butFbLogin = (LoginButton)findViewById(R.id.but_fb_login); assert butFbLogin != null; mLoginCallbackManager = CallbackManager.Factory.create(); butFbLogin.setReadPermissions("email"); butFbLogin.registerCallback(mLoginCallbackManager, new FacebookCallback<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { if(loginResult.getAccessToken() != null){ Intent intent = new Intent(LoginActivity.this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); }else{ Log.e(TAG, "Returned FB access token null"); } } @Override public void onCancel() { //TODO } @Override public void onError(FacebookException error) { error.printStackTrace(); Toast.makeText(LoginActivity.this, "Error Login to Facebook", Toast.LENGTH_LONG).show(); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data){ super.onActivityResult(requestCode, resultCode, data); mLoginCallbackManager.onActivityResult(requestCode, resultCode, data); }
The login page is rather straight forward. Few things need to be careful: Facebook.sdkInitialized() must be called before setContentView(). It seems that parts of XML of widgets provided by SDK is modified or generated dynamically. Also, if a user revoke permission for your app from her account, AccessToken.getCurrentAccessToken() would still return non-null result. So you may need extra care during API calls.