安卓 - Facebook SDK 3 - 如何在没有LoginButton的情况下通过编程方式登录

39

我正在编写一个与Facebook SDK集成的应用程序,用于将某些(字符串)内容作为墙贴发布。现在,我已经成功实现了HelloFacebookSample。然而它使用他们的LoginButton来登录用户。

我不想要这样。我只想在操作栏中点击我的共享按钮并将其分享到Facebook。因此,我想编程方式登录,我尝试模拟LoginButton的操作,但迄今为止没有成功。 我得到以下错误:

12-06 15:34:33.180: E/AndroidRuntime(19493): java.lang.UnsupportedOperationException: Session: an attempt was made to reauthorize a session that has a pending request.

public class MainActivity extends FacebookActivity {

@SuppressWarnings("serial")
private static final List<String> PERMISSIONS = new ArrayList<String>() {
    {
        add("publish_actions");
    }
};
private final int REAUTHORIZE_ACTIVITY = 3;
private Button postStatusUpdateButton;
private PendingAction pendingAction = PendingAction.NONE;

private enum PendingAction {
    NONE, POST_PHOTO, POST_STATUS_UPDATE
}

/**
 * Called when the activity is first created.
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    postStatusUpdateButton = (Button) findViewById(R.id.postStatusUpdateButton);
    postStatusUpdateButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {
            Log.d("MainActivity", "onClick");
            onClickPostStatusUpdate();
        }

    });

}

@Override
protected void onSessionStateChange(SessionState state, Exception exception) {
    super.onSessionStateChange(state, exception);
}

private interface GraphObjectWithId extends GraphObject {
    String getId();
}

private void showPublishResult(String message, GraphObject result, FacebookRequestError error) {
    String title = null;
    String alertMessage = null;
    if (error == null) {
        title = getString(R.string.success);
        String id = result.cast(GraphObjectWithId.class).getId();
        alertMessage = getString(R.string.successfully_posted_post, message, id);
    } else {
        title = getString(R.string.error);
        alertMessage = error.getErrorMessage();
    }

    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(title).setMessage(alertMessage).setPositiveButton(getString(R.string.ok), null);
    builder.show();
}

private void onClickPostStatusUpdate() {
    Log.d("MainActivity", "onClickPostStatusUpdate");
    performPublish(PendingAction.POST_STATUS_UPDATE);
}

private boolean hasPublishPermission() {
    Session session = Session.getActiveSession();
    return session != null && session.getPermissions().contains("publish_actions");
}

private void performPublish(PendingAction action) {
    Log.d("MainActivity", "peformPublish");

    Session session = Session.getActiveSession();

    if (session == null) {
        session = new Session.Builder(this).setApplicationId("xxx").build();
        Session.setActiveSession(session);
    }

    if (!session.isOpened()) {
        Session.OpenRequest openRequest = new Session.OpenRequest(this);
        openRequest.setPermissions(PERMISSIONS);
        openRequest.setLoginBehavior(SessionLoginBehavior.SSO_WITH_FALLBACK);
        session.openForPublish(openRequest);
    }

    if (session != null) {
        // postStatusUpdate();
        pendingAction = action;
        if (hasPublishPermission()) {
            // We can do the action right away.
            handlePendingAction();
            // postStatusUpdate();
        } else {
            // We need to reauthorize, then complete the action when we get
            // called back.
            Session.ReauthorizeRequest reauthRequest = new Session.ReauthorizeRequest(this, PERMISSIONS)
                    .setRequestCode(REAUTHORIZE_ACTIVITY).setLoginBehavior(SessionLoginBehavior.SSO_WITH_FALLBACK);
            session.reauthorizeForPublish(reauthRequest);
        }
    }
}

@SuppressWarnings("incomplete-switch")
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;

    switch (previouslyPendingAction) {
    case POST_STATUS_UPDATE:
        postStatusUpdate();
        break;
    }
}

private void postStatusUpdate() {
    // if (user != null && hasPublishPermission()) {
    if (hasPublishPermission()) {
        // final String message = getString(R.string.status_update,
        // user.getFirstName(), (new Date().toString()));
        final String message = "kks uz nemam nervy";
        Request request = Request.newStatusUpdateRequest(Session.getActiveSession(), message,
                new Request.Callback() {
                    @Override
                    public void onCompleted(Response response) {
                        showPublishResult(message, response.getGraphObject(), response.getError());
                    }
                });
        Request.executeBatchAsync(request);
    } else {
        pendingAction = PendingAction.POST_STATUS_UPDATE;
    }
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Log.d("MainActivity", "onActivityResult");
    Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);
}

嗯,这仍然是HelloFacebookSample项目,我正在尝试正确地使用它。我唯一尝试过的是performPublish方法以及与创建会话有关的东西。

希望有更简单的方法!附言:我正在使用Facebook SDK 3


1
我遇到了同样的问题,你是如何解决的? - Muhammad Umar
请注意,在最近的SDK版本中,Session.ReauthorizeRequest已经不存在了。您可以在此代码的基础上找到一个更新的工作示例这里 - sgdesmet
3个回答

21

你发布的是否是完整的Activity?

你还需要覆盖onActivityResult,并将值传递给Session.getActiveSession().onActivityResult(...)。否则,Session不会知道用户已经授权了你的应用程序,这就是为什么会出现错误的原因(Session认为仍有待处理的授权请求,这就是为什么你无法重新授权发布的原因)。


我发布了完整的源代码,但是performPublish中的代码只是修补过的,实际上我不知道自己在做什么...暴露了appId等等...(难道没有正常的方式来编写程序登录吗?)也许我应该退后一步,如何仅通过编程方式登录,而不发布状态更新呢? - urSus
77
个人认为新的API或者示例/教程非常糟糕,至少在我的眼里是这样。最终我只好将整个精致的教程复制到我的应用程序中来完成我想要的操作,而该教程的95%都是处理片段、布局、活动和其他与核心点无关的内容:使这个API工作。原本应该很简单的事情变得异常复杂,完全没有必要这样。我想知道他们是否真的会放弃Facebook对象并在此之前明确说明一些事情。 - Beppi's
我尝试使用UILifeCycleHelper实现FB登录流程,在某些情况下,通常包含FB响应的字段“mMap”的data参数为空。 有人知道这是为什么吗? - Etienne Lawlor
2
花了我两天时间才找到这个答案,这个步骤应该在他们的教程中说明。 - eliocs
我刚开始使用Facebook API,之前用过Parse等API。他们需要解雇他们的Android开发人员,可能是我用过的最糟糕的API。 - Oliver Dixon
显示剩余3条评论

18

由于我和许多在这里点赞@Beppi的评论以及@Ming Li的回答的人有相同的感觉,同时我在我的应用程序中使用Facebook SDK,因此我决定创建一个更简化的API级别,该级别基于最新的Facebook SDK 3.0.b。

开源库:android-simple-facebook
https://github.com/sromku/android-simple-facebook

回答你的问题:如何通过编程方式登录?

  1. 设置登录/注销监听器

// set login / logout listener
OnLoginOutListener onLoginOutListener = new SimpleFacebook.OnLoginOutListener()
{

    @Override
    public void onFail()
    {
        Log.w(TAG, "Failed to login");
    }

    @Override
    public void onException(Throwable throwable)
    {
        Log.e(TAG, "Bad thing happened", throwable);
    }

    @Override
    public void onThinking()
    {
        // show progress bar or something to the user while login is happening
        Log.i(TAG, "In progress");
    }

    @Override
    public void onLogout()
    {
        // change the state of the button or do whatever you want
        Log.i(TAG, "Logged out");
    }

    @Override
    public void onLogin()
    {
        // change the state of the button or do whatever you want
        Log.i(TAG, "Logged in");
    }
};

// set the listener
mSimpleFacebook.setLogInOutListener(onLoginOutListener);
  • 点击任何视图,只需调用login(Activity)方法

  • mSimpleFacebook.login(MainActivity.this);
    
  • 登出请调用logout()方法。像这样:

  • mSimpleFacebook.logout();
    
    如何在登录前设置权限,请查看这里提供的友好解释。
    希望对某些人有所帮助 :)

    2
    非常有用的库!节省了我很多时间。感谢您提供它。 - Gunnar Karlsson
    4
    谢谢。Facebook SDK 现在和以后都很糟糕。我不知道架构师设计 API 时想的是什么,但他显然有一个非常奇怪的想法。结果就是有许多垃圾的 Android 应用程序会经常(随机地)失败或抛出晦涩难懂的消息。 - Martin Marconcini
    这很不错!只是希望它支持通过图形 API 发布。 - Kon
    @Kon 它支持通过图形 API 发布动态、照片、视频和分数。 - sromku
    @sromku 我昨晚花了更多时间才弄明白这个问题。但我正在寻找Like支持。我看到有一个拉取请求添加了Like支持。希望它能很快被合并到主分支中。 - Kon
    非常有用和聪明,谢谢!请注意,在OnPublishListener - onComplete中检查postId不为空才能成功。 - djdance

    1

    非常棒的代码,谢谢。

    请注意,在v3 SDK版本中,重新授权代码必须替换为:

    Session.NewPermissionsRequest reauthRequest = new Session.NewPermissionsRequest(FacebookActivity.this, PERMISSIONS)
                                    .setRequestCode(REAUTHORIZE_ACTIVITY)
                                    .setLoginBehavior(SessionLoginBehavior.SSO_WITH_FALLBACK);
                            session.requestNewPublishPermissions(reauthRequest);
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接