12

条件:安装了本机 Facebook apk 但已注销的 Android 设备。

每次满足此条件并且用户尝试使用 Facebook 的LoginButton或手动登录(见下文)时,登录后,Facebook SDK 总是会请求访问用户数据的权限,即使用户已经授予权限.

这是我在我的应用程序上实现的代码:

版本 1 - 登录按钮:

XML:

<com.facebook.widget.LoginButton
    android:id="@+id/login_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

爪哇:

private static final List<String> PERMISSIONS = Arrays.asList("email", "user_groups");
private UiLifecycleHelper uiHelper;

@Override
protected void onCreate(Bundle savedInstanceState){
    uiHelper = new UiLifecycleHelper(this, callback);
    uiHelper.onCreate(savedInstanceState);
    loginButton = (LoginButton) findViewById(R.id.login_button);
    loginButton.setReadPermissions(PERMISSIONS);
}

private Session.StatusCallback callback = new Session.StatusCallback() {
    @Override
    public void call(Session session, SessionState state, Exception exception) {
        //modify interface or something
    }
};

版本 2 - 手动

XML:

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/button"
    android:onClick="buttonOnClick"
    android:text="Login" />

爪哇:

private static final List<String> PERMISSIONS = Arrays.asList("email", "user_groups");

public void buttonOnClick(View v) {
    System.out.println("botaoOnClick");
    Session session = Session.getActiveSession();
    if (!session.isOpened() && !session.isClosed()) {
        System.out.println("session: " + session);
        session.openForRead(new Session.OpenRequest(this).setPermissions(PERMISSIONS).setCallback(callback));
    }
    else {
        Session.openActiveSession(this, true, callback);
    }
}

private Session.StatusCallback callback = new Session.StatusCallback() {
    @Override
    public void call(Session session, SessionState state, Exception exception) {
        //modify interface or something
    }
};

即使是 sdk 附带的示例应用程序也以这种方式工作,但我已经看到其他一些应用程序(例如 Foursquare)以我认为的自然行为方式工作(仅在用户尚未授予权限时才请求权限)。

那么,有没有人知道达到预期结果的方法?最好不要编辑 Facebook SDK 本身。

提前致谢!

编辑1:附加信息:在回调方法上检查会话变量时,满足上述条件时,权限始终为空。如果用户拒绝授予权限(不是第一次),并尝试再次登录,会话将具有用户在过去一段时间内已经授予的权限,正如预期的那样。

编辑 2(2013 年 6 月 28 日):我决定上传一段重现该问题的视频,因为我不太确定每个人都理解我在解释中的意思。

链接在这里:http ://www.youtube.com/watch?v=w4qJfoiVSsU

4

4 回答 4

2

那可能是因为您的应用程序(我假设它处于调试模式)和与您的 appID 关联的 Facebook 应用程序之间存在签名不匹配。

基本上你应该确保:

  1. 使用 facebook sdk 的 android 应用程序的签名已添加到facebook 应用程序仪表板 Facebook 应用仪表板 ,您可以使用 keytool 或在活动的 onCreate 方法中添加此代码轻松获取应用程序签名:

    @Override
    protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    
    try {
        PackageInfo info = getPackageManager().getPackageInfo(
                getPackageName(), 
                PackageManager.GET_SIGNATURES);
        for (Signature signature : info.signatures) {
            MessageDigest md = MessageDigest.getInstance("SHA");
            md.update(signature.toByteArray());
            Log.d("TAG", "Hash to copy ==> "+ Base64.encodeToString(md.digest(), Base64.DEFAULT));
            }
    } catch (NameNotFoundException e) {
    
    } 
    catch (NoSuchAlgorithmException e) {
    
    }
    }
    
  2. Facebook 登录复选框已启用

  3. 如果您未启用沙盒模式,则需要从应用详细信息页面中选择一个类别

  4. 默认情况下,登录按钮使用 SingleSignOn 登录行为,它基本上会让您以 facebook 应用程序的所有者身份登录,我建议您使用允许任何用户代表您的 facebook 应用程序登录的那个。为此,只需在为登录按钮设置权限后添加此行:

    loginButton.setReadPermissions(PERMISSIONS);
    loginButton.setLoginBehavior(SessionLoginBehavior.SUPPRESS_SSO);
    

如果您仍然遇到问题,我建议您阅读此文档疑难解答 facebook 登录

PS:仅供参考,如果您使用 UiLifecycleHelper,请不要忘记覆盖主要的活动/片段生命周期方法,并将调用转发到 javadoc 中所述的 UiLifecycleHelper。

使用此类时,客户端必须从 Activity 或 Fragment 中的 * 各自方法调用所有公共方法。未能调用所有 * 方法可能会导致未正确初始化或未初始化的 Sessions。

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
protected void onResume() {
    super.onResume();
    uiHelper.onResume();
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    uiHelper.onSaveInstanceState(outState);
}

@Override
protected void onPause() {
    super.onPause();
    uiHelper.onPause();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    uiHelper.onDestroy();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    uiHelper.onActivityResult(requestCode, resultCode, data);
}
于 2013-06-24T19:04:44.407 回答
0

如果设备上未安装 Facebook 应用程序,我认为每次都会请求读取权限(或者只是显示一个弹出窗口,说明它们已被授予)。

它应该是最后一个 Android SDK 的行为。

您是否注意到也安装了该应用程序?

于 2013-06-24T19:17:12.067 回答
0

我已经确定了导致此问题的两个原因。

  1. 需要在手动版本的代码中传递权限,即 openActiveSession(),为此我使用具有权限的 openForRead(op)。
  2. KeyHash 不匹配,在这种情况下,在默认 facebook 中也可以成功登录,但每次都显示权限对话框。

我使用 debug.keystore 和以下命令创建了 KeyHash

keytool -exportcert -alia
s androiddebugkey -keystore debug.keystore | ope
nssl sha1 -binary | openssl base64

private static final List<String> PERMISSIONS = Arrays.asList("email", "user_groups");

public void buttonOnClick(View v) 
{
    Log.e("SKFBDemo", "buttonOnClick");

    Session session = Session.getActiveSession();
    if (session != null && !session.isOpened() && !session.isClosed()) 
    {

        Log.e("SKFBDemo", "Session is in Active");
        session.openForRead(new Session.OpenRequest(this).setPermissions(PERMISSIONS).setCallback(callback));
    }
    else 
    {
        Log.e("SKFBDemo", "Session is null or not opened or closed");

        OpenRequest op = new Session.OpenRequest(this);
        op.setPermissions(PERMISSIONS);

        session = new Builder(this).build();
        session.addCallback(callback);
        Session.setActiveSession(session);
        session.openForRead(op);
    }
}

private Session.StatusCallback callback = new Session.StatusCallback() 
{
    @Override
    public void call(Session session, SessionState state, Exception exception) 
    {
        Log.e("SKFBDemo", "Session.StatusCallback state="+state.toString());
    }
};

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    Log.e("SKFBDemo", "onActivityResult resultCode="+resultCode);

    if(resultCode == RESULT_OK && requestCode == Session.DEFAULT_AUTHORIZE_ACTIVITY_CODE)
    {
        Session.getActiveSession().onActivityResult(this, requestCode, resultCode, data);

        final Session session = Session.getActiveSession(); 
        if (session != null && !session.isClosed()) 
        {
            Log.e("SKFBDemo", "Login successful");
        }
        else
        {
            Log.e("SKFBDemo", "Facebook session not opened");
        }
    }
}

我尝试使用此代码,它只询问权限对话框一次并且工作正常。

于 2013-06-27T08:30:04.343 回答
0

我使用手动版本,稍微改变了 buttonOnClick 函数中的 if 语句。

Session session = Session.getActiveSession();
boolean isReadAllowed = checkPermissions(Arrays.asList(PERMISSIONS), session.getPermissions());
if (!session.isOpened() && !session.isClosed()) {
    session.openForRead(new Session.OpenRequest(this).setPermissions(PERMISSIONS).setCallback(callback));
} else {
    if (isReadAllowed) {
        Session.openActiveSession(this, true, callback);
    } else {                                    
        session.requestNewReadPermissions(new Session.NewPermissionsRequest(this, Arrays.asList(PERMISSIONS)).setCallback(callback));
    }
}

还有我的 checkPermissions 函数:

public static boolean checkPermissions(List<String> needed, List<String> available) {
    boolean ret = true;
    for (String s : needed) {
        if (!available.contains(s)) {
            ret = false;
            break;
        }
    }
    return ret;
}

我的流程有效,并且仅在未授予权限时才请求权限。你能粘贴更多的回调代码吗?我可以检查你是否在那里做一些不同的事情。

编辑:谢谢你的视频。我最初不明白这个问题。我以前见过这种行为,这是 Facebook SDK 的一个错误。一个月前我在他们的跟踪器(链接)上提交了一个错误,看起来他们不会修复它。

于 2013-06-26T06:16:17.733 回答