Android FacebookSDK для входа в систему с помощью встроенного приложения Facebook запрашивает разрешения даже после того, как пользователь уже дал им
Состояние: Android-устройство с встроенным Facebook apk установлено, но вышло из системы.
Каждый раз, когда это условие выполняется, и пользователь пытается войти с помощью Facebook LoginButton или делать это вручную (см. ниже), после во время входа в систему, SDK Facebook всегда запрашивает разрешение на доступ к пользовательским данным, даже если пользователь уже дал разрешение.
Вот код, который я реализую в своем приложении:
Версия 1 - Кнопка входа в систему:
XML:
<com.facebook.widget.LoginButton
android:id="@+id/login_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Java:
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" />
Java:
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), работающие так, как я считаю, это естественное поведение (только запрашивает разрешения, если пользователь hasn ' t уже дал им).
Итак, кто-нибудь знает способ достижения желаемого результата? Предпочтительно без редактирования самого SDK Facebook.
Спасибо заранее!
Изменить 1. Дополнительная информация: при проверке переменной сеанса на методе обратного вызова разрешения всегда становятся пустыми, когда выполняется условие выше. Если пользователь отказывается давать разрешение (не в первый раз) и пытается снова войти в систему, сеанс приходит с разрешениями, которые пользователь уже дал в прошлом, как и ожидалось.
Изменить 2 (в 2013-06-28). Я решил загрузить видео, воспроизводя проблему, так как я не уверен, что все понимают, что я имел в виду в своем объяснении.
Ссылка здесь: http://www.youtube.com/watch?v=w4qJfoiVSsU
Ответы
Ответ 1
Это возможно потому, что у вас есть несоответствие подписи между вашим приложением (которое, как я полагаю, находится в режиме отладки), и ваше приложение facebook, связанное с вашим appID.
В основном вы должны убедиться, что:
-
Подпись вашего приложения для Android, использующего facebook sdk, добавляется в панель инструментов facebook app
вы можете легко получить свою подпись приложения с помощью keytool или добавив этот код в свою деятельность по методу WithCreate:
@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) {
}
}
-
Флажок входа в Facebook включен
-
Если в вашем небезопасном режиме песочницы вам нужно выбрать категорию на странице сведений о приложении
-
По умолчанию в loginbutton используется имя входа SingleSignOn, которое будет в основном регистрироваться в качестве владельца приложения facebook, поэтому я предлагаю вам использовать тот, который позволяет любому пользователю входить в систему от имени вашего приложения facebook. Для этого просто добавьте эту строку после того, как вы установите разрешение на кнопку входа:
loginButton.setReadPermissions(PERMISSIONS);
loginButton.setLoginBehavior(SessionLoginBehavior.SUPPRESS_SSO);
Если у вас все еще есть проблемы, я предлагаю вам прочитать этот документ устранение неполадок в facebook login
PS: И FYI. Если вы используете UiLifecycleHelper, не забудьте переопределить основные методы жизненного цикла активности/фрагмента и перенаправить вызовы на UiLifecycleHelper, как указано в javadoc.
При использовании этого класса клиенты ДОЛЖНЫ вызывать все общедоступные методы из * соответствующие методы либо в Деятельности, либо в фрагменте. Невыполнение всех * методы могут привести к неправильно инициализированным или неинициализированным сеансам.
@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);
}
Ответ 2
Я думаю, что разрешения на чтение запрашиваются каждый раз (или просто показывают всплывающее высказывание, которое они уже предоставили), если приложение Facebook не установлено на устройстве.
Это должно быть поведение с последним Android SDK.
Вы заметили, что с установленным приложением тоже?
Ответ 3
Я использую ручную версию с небольшим завихрением для оператора if в вашей функции buttonOnClick.
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;
}
Мой поток работает и только запрашивает разрешения, если они не были предоставлены. Можете ли вы вставить больше своего кода обратного вызова? Я могу проверить, делаете ли вы что-то другое.
EDIT: Спасибо за видео. Сначала я не понял проблему. Я видел это поведение раньше, и это ошибка с помощью SDK для Facebook. Я подал ошибку на свой трекер (ссылка) месяц назад, похоже, что они не исправят это.
Ответ 4
Я определил две причины этой проблемы.
- Необходимо передать разрешения в блоке else в ручной версии вашего кода, то есть openActiveSession(), для этого я использую openForRead (op) с разрешениями.
- KeyHash не подходит, и в этом случае также успешно выполняется вход в систему по умолчанию, но каждый раз отображается диалог разрешений.
Я создал KeyHash с помощью debug.keystore со следующей командой
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");
}
}
}
Я пробовал с этим кодом, его запрос разрешения только один раз и работает нормально.