2

我已经将 Facebook SDK(目前是 3.5,但我从 3.0 开始)实现到一个 Android 应用程序中。根据Facebook 最佳实践,我需要提供一个退出选项。问题是我第一次登录它可以工作,但在注销并尝试再次登录后就不行了。

我的应用程序有一个BaseActivity处理大部分共享代码(包括登录)的应用程序,并由两个类扩展:FacebookLoginActivity用于登录 UI 和ViewActivity用于在登录后显示信息。

这是我正在使用的代码,稍作编辑以删除不相关的方法:
[BaseActivity]

package uk.co.cgfindies.wittylater;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;

import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.facebook.Session;
import com.facebook.SessionState;
import com.testflightapp.lib.TestFlight;

public class BaseActivity extends SherlockFragmentActivity {

    public static final int ACTIVITY_FACEBOOK_LOGIN = 0;
    public static final List<String> BASIC_PERMISSIONS = Arrays.asList("basic_info");
    public static final List<String> READ_PERMISSIONS = Arrays.asList("basic_info", "read_stream");
    public static final List<String> PUBLISH_PERMISSIONS = Arrays.asList("publish_actions");
    public static final String GENERIC_TAG = "WITTYLATER";
    public static final String PROFILE_PICTURE_CACHE_UNIQUE_NAME = "fb_profile_pictures";
    public static final int PROFILE_PICTURE_CACHE_SIZE = 1024 * 1024 * 1;
    public static final int DEFAULT_LIKES_REFRESH_INTERVAL_IN_MINUTES = 15;
    private static final String PENDING_PUBLISH_KEY = "pendingPublishReauthorization";
    private static final String FACEBOOK_LOGIN_TAG = "FACEBOOK_LOGIN_TAG";
    public static final int NOTIFICATION_POST_UPDATED = 1;
    public static final String ARGS_BOOLEAN_SHOW_MENU = "ARGS_NO_MENU";
    public static final String ARGS_BOOLEAN_FACEBOOK_LOGIN = "ARGS_BOOLEAN_FACEBOOK_LOGIN";

    private boolean facebookLogin = false;  // This will be true if the system is currently trying to log the user in.
    private boolean showMenu = true;
    protected static boolean pendingPublishReauthorization;
    private static String username = "";
    private Session.StatusCallback statusCallback = new SessionStatusCallback();
    private static SessionState currentState;

    private Context context;

  private class SessionStatusCallback implements 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);
        init(savedInstanceState);
    }

  ...

    private void init(Bundle savedInstanceState) {
        Log.i(BaseActivity.GENERIC_TAG, "init: " + this.getClass().getName());

    Session session = Session.getActiveSession();
    if (session == null) {
        if (savedInstanceState != null) {
            session = Session.restoreSession(this, null, statusCallback, savedInstanceState);
        }
        if (session == null) {
            session = new Session(this);
        }
        Session.setActiveSession(session);
        if (session.getState().equals(SessionState.CREATED_TOKEN_LOADED)) {
            session.openForRead(new Session.OpenRequest(this).setCallback(statusCallback));
        }
    }

    if (!session.isOpened() && !(this instanceof FacebookLoginActivity)) {
        Log.i(BaseActivity.GENERIC_TAG, "Starting FacebookLoginActivity");
            Intent i = new Intent(this, FacebookLoginActivity.class);
            this.startActivity(i);
            this.finish();
            return;
    }

        if (!SyncWithFacebookService.isServiceRunning()) {
            Intent intent = new Intent(this, SyncWithFacebookService.class);
            startService(intent);
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        Session.getActiveSession().addCallback(statusCallback);
    }

    @Override
    public void onStop() {
        super.onStop();
        Session.getActiveSession().removeCallback(statusCallback);
    }

    @Override
    public void onResume() {
        Log.i(BaseActivity.GENERIC_TAG, this.getClass().getName() + " onResume()");
        super.onResume();
        Session session = Session.getActiveSession();
        onSessionStateChange(session, session.getState(), null);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.i(BaseActivity.GENERIC_TAG, this.getClass().getName() + " onActivityResult request: " + requestCode);
        super.onActivityResult(requestCode, resultCode, data);
        Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        Log.i(BaseActivity.GENERIC_TAG, this.getClass().getName() + " onSaveInstanceState()");
        super.onSaveInstanceState(outState);
        Session session = Session.getActiveSession();
    Session.saveSession(session, outState);
    }

    protected void onSessionStateChange(Session session, SessionState state, Exception exception) {
        Log.i(BaseActivity.GENERIC_TAG, "onSessionStateChange called from " + this.getClass().getName());
        Log.i(BaseActivity.GENERIC_TAG, "current state is " + ((currentState == null) ? "null" : currentState.toString()));
        Log.i(BaseActivity.GENERIC_TAG, "state is " + state.toString());

        if (state.equals(currentState)) {
            Log.i(BaseActivity.GENERIC_TAG, "state hasn't changed, returning.");
            return;
        }

        currentState = state;

        if (exception != null) {
            Log.d(BaseActivity.GENERIC_TAG, exception.getMessage());
            TestFlight.log(exception.getMessage());
        }

        if (state.isOpened()) {
            Log.i(BaseActivity.GENERIC_TAG, "Starting FetchFacebookDataActivity");
            Intent i = new Intent(this, FetchFacebookDataActivity.class);
            i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(i);
            finish();
        }
    }

    public void startLogin(View v) {
        Log.i(BaseActivity.GENERIC_TAG, this.getClass().getName() + " startLogin()");
        Session session = Session.getActiveSession();

        if (session != null && !session.isClosed()) {
            Log.i(BaseActivity.GENERIC_TAG, "Closing Session, clearing tokens");
            session.closeAndClearTokenInformation();
        }

        if (!session.getState().isOpened() && !session.getState().isClosed()) {
            Log.i(BaseActivity.GENERIC_TAG, "Session state is " + session.getState().toString() + ", opening for read.");
            session.openForRead(new Session.OpenRequest(this).setCallback(statusCallback));
        } else {
            Log.i(BaseActivity.GENERIC_TAG, "Opening new active session");
            Session.openActiveSession(this, true, statusCallback);
        }

    }

    public void facebookLogout() {
        Log.i(BaseActivity.GENERIC_TAG, "Logging out.");
        Session session = Session.getActiveSession();
        if (!session.isClosed()) {
            Log.i(BaseActivity.GENERIC_TAG, "Clearing Facebook tokens.");
            session.closeAndClearTokenInformation();
        }

        Log.i(BaseActivity.GENERIC_TAG, "Starting FacebookLoginActivity");
        startNewActivity(FacebookLoginActivity.class, true, true);
        finish();
        return;
    }

    protected void startNewActivity(Class<?> cls, boolean clearTop, boolean finish) {
        Log.i(BaseActivity.GENERIC_TAG, "Current class is " + this.getClass().getName());
        Log.i(BaseActivity.GENERIC_TAG, "Target class is " + cls.getName());
        Log.i(BaseActivity.GENERIC_TAG, Boolean.toString(cls.isInstance(this)));
        Log.i(BaseActivity.GENERIC_TAG, Boolean.toString(cls.isInstance(this.getClass())));
        Log.i(BaseActivity.GENERIC_TAG, Boolean.toString(this.getClass().isInstance(cls)));

        if (cls.isInstance(this)) {
            Log.i(BaseActivity.GENERIC_TAG, "Already instance of " + cls.getName());
            return;     // Already in that activity.
        }

        Log.i(BaseActivity.GENERIC_TAG, "Starting class " + cls.getName());
        Intent i = new Intent(this, ViewActivity.class);
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(i);
        finish();
    }
}

[Facebook登录活动]

package uk.co.cgfindies.wittylater;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;

public class FacebookLoginActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i(BaseActivity.GENERIC_TAG, this.getClass().getName() + " onCreate()");
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_facebook_login);

        FacebookLoginFragment flf = new FacebookLoginFragment();
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.facebook_login_container, flf);
        fragmentTransaction.commit();
    }
}

[Facebook登录片段]

package uk.co.cgfindies.wittylater;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.actionbarsherlock.app.SherlockFragment;

public class FacebookLoginFragment extends SherlockFragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.i(BaseActivity.GENERIC_TAG, this.getClass().getName() + " onCreateView()");
        super.onCreateView(inflater, container, savedInstanceState);
        View v = inflater.inflate(R.layout.fragment_facebook_login, container, false);
        return v;
    }
}

[ViewActivity] 包 uk.co.cgfindies.wittylater;

import uk.co.cgfindies.wittylater.ViewPostedFragment.ViewPostedFragment_onClickListeners;
import uk.co.cgfindies.wittylater.ViewUnpostedFragment.ViewUnpostedFragment_onClickListeners;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;

import com.actionbarsherlock.view.Menu;

public class ViewActivity extends BaseActivity implements ViewUnpostedFragment_onClickListeners, ViewPostedFragment_onClickListeners {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view);
        ...
    }
}

据我所知,它尝试登录的秒数会Session.openActiveSession()触发 call ,BaseActivity.onSessionStateChange()然后启动并ViewActivity.onCreate()调用一个意图。这意味着登录的活动结果无处可去。我已经尝试了大约 20 个小时以来我能想到的一切,但我无法弄清楚出了什么问题。

为什么ViewActivity突然被创造出来?可能是因为它被设置为启动器活动,也可能是因为它在 Facebook 应用程序设置中被列为应用程序类名称,但除此之外我不知道。

4

2 回答 2

0

我终于想通了,我完全看错了地方。

在另一个类中,我使用的是 FacebookUiLifecycleHelper类,但我忘记实现一些 Android 生命周期方法,例如onPauseonDestroy.
这意味着它UiLifecycleHelper仍然处于活动状态并导致各种问题。一旦解决了这个问题,登录/注销就可以完美地工作了。

于 2013-09-18T12:15:17.683 回答
0

问题可能是您上传的哈希键和我从下面的代码中得到的不同。试试这个代码这个代码,在控制台中获取哈希码,在 facebook 控制台上更新它,它会完美登录。我发布这个是为了让我的开发人员节省一些我在解决这个问题上花费的时间。

try {
PackageInfo info = getPackageManager().getPackageInfo(
      "com.facebook.samples.loginhowto", PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures){
       MessageDigest md = MessageDigest.getInstance("SHA");
       md.update(signature.toByteArray());
       Log.d("KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT));
}
} catch (NameNotFoundException e) {
} catch (NoSuchAlgorithmException e) {
}
于 2014-08-12T11:32:55.783 回答