Android 8.0 Oreo — Аккаунты

В моем приложении мне нужно знать, есть ли какая-либо учетная запись Google или учетная запись Samsung.

До Android 7 эту информацию было легко получить с помощью чего-то вроде:

    Account[] accounts = AccountManager.get(getContext())
.getAccountsByType("com.google")

Но с событием Oreo это уже не работает.

РЕДАКТИРОВАТЬ: см. официальную информацию по этому вопросу: В Android 8.0 (уровень API 26) приложения больше не могут получать доступ к учетным записям пользователей, если аутентификатор не владеет учетными записями или пользователь не предоставляет этот доступ. Разрешения GET_ACCOUNTS больше недостаточно. Чтобы получить доступ к учетной записи, приложения должны либо использовать AccountManager.newChooseAccountIntent(), либо метод, специфичный для аутентификатора. Получив доступ к учетным записям, приложение может вызвать AccountManager.getAccounts() для доступа к ним. Android 8.0 не поддерживает LOGIN_ACCOUNTS_CHANGED_ACTION. Вместо этого приложения должны использовать addOnAccountsUpdatedListener() для получения обновлений об учетных записях во время выполнения. Информацию о новых API и методах, добавленных для доступа к учетной записи и возможности обнаружения, см. в разделе Доступ к учетной записи и возможность обнаружения в разделе Новые API этого документа

Я потратил полдня, чтобы найти решение моей потребности, но безуспешно.

Я нашел информацию, утверждающую, что теперь единственный способ получить доступ к учетным записям — это использовать AccountPicker следующим образом:

AccountPicker.newChooseAccountIntent(null, null, new String[]{"com.google"},true, null, null, null, null);

Но это отвечает на мою проблему. Чтобы было ясно, мне нужно только знать, существует ли учетная запись для определенного типа (Google, Samsung...). Мне не нужно знать, сколько, и мне не нужна информация об учетных записях.


person Steeve Favre    schedule 29.09.2017    source источник
comment
что вы имеете в виду под этим больше не работает? Можете ли вы предоставить какой-нибудь код, журнал или трассировку стека, все, что кажется вам важным, чтобы сообщество могло вам помочь?   -  person Benjamin    schedule 29.09.2017
comment
Я имею в виду, что метод getAccount() больше не возвращает данные учетной записи, за исключением учетных записей, связанных с приложением.   -  person Steeve Favre    schedule 29.09.2017
comment
Вот более подробная информация из официальной документации: В Android 8.0 (уровень API 26) приложения больше не могут получать доступ к учетным записям пользователей, если аутентификатор не владеет учетными записями или пользователь не предоставляет этот доступ.   -  person Steeve Favre    schedule 29.09.2017
comment
@Steve Favre, можете ли вы поделиться ссылкой на это и расскажите, пожалуйста, как это можно решить.   -  person Nikhil Singh    schedule 28.09.2018
comment
Пожалуйста, смотрите мой ответ. Вот как у вас это работает   -  person AndyB    schedule 04.10.2018
comment
Здесь упоминается подробный подход: stackoverflow.com/a/53693072/6886397   -  person Vasudevan Nair R    schedule 09.12.2018


Ответы (3)


Использование разрешения «android.permission.READ_CONTACTS» и

    Account[] accounts = AccountManager.get(getContext())
.getAccountsByType("com.google") 

снова работает в Android Oreo

person nguyenvangiangbn    schedule 02.10.2018

Как вы уже сказали, невозможно прочитать другие учетные записи, если пользователь не дал вам на это разрешения. Разрешение теперь предоставляется не только с разрешением во время выполнения, но даже с помощью средства выбора учетной записи, то есть учетная запись видна вашему приложению, только если пользователь выбрал учетную запись после того, как вы вызвали средство выбора учетной записи. Это новое ограничение предназначено именно для того, чтобы избежать того, что вы пытаетесь сделать: прочитать все учетные записи пользователей. У вашей проблемы нет решения, единственное, что вы можете сделать, это предоставить пользователю средство выбора и позволить ему выбрать все учетные записи, однако это не лучший пользовательский опыт.

Изменить: начиная с Сервисов Google Play 11.6 появился новый метод requestGoogleAccountsAccess() для получения всех учетных записей Google.

person greywolf82    schedule 01.10.2017
comment
Как я уже сказал, я НЕ хочу читать какую-либо информацию об аккаунтах. Мне просто нужно знать, существует ли он для определенного типа, вот и все. Но я думаю, что вы правы, что даже для этого нет решения. - person Steeve Favre; 02.10.2017
comment
Я знаю, что уже поздно, поэтому я опубликую только для будущих читателей. Информация о том, существует ли учетная запись, по-прежнему является информацией, для получения которой вам необходим доступ. IE: пользователь может не хотеть, чтобы вы знали, какие учетные записи существуют, поскольку существование учетной записи само по себе является частной информацией. - person Aaron T Harris; 19.06.2018
comment
@AaronTHarris расскажите, пожалуйста, как решить эту проблему, как я могу получить имя пользователя из связанной учетной записи Google. - person Nikhil Singh; 28.09.2018
comment
Пожалуйста, смотрите мой ответ. Вот как у вас это работает - person AndyB; 04.10.2018

Чтобы получить установленные учетные записи Google на устройстве под управлением Oreo+ (8+) с помощью этого кода

 Account[] accounts = AccountManager.get(getContext()).getAccountsByType("com.google")

Вам нужно сначала позвонить

https://developers.google.com/android/reference/com/google/android/gms/auth/GoogleAuthUtil.html#requestGoogleAccountsAccess(android.content.Context)

Сначала добавьте следующую зависимость

com.google.android.gms:play-services-auth:16.0.0

Вызов requestGoogleAccountsAccess() генерирует исключение, которое вы можете привести (после проверки) к UserRecoverableAuthException и получить от него намерение начать с startActivityForResult

Вот пример кода, работающего на Android Oreo

// call this on a background thread!
private void requestGoogleAccountAccess() throws Exception
{
    googleAccountAccessGranted = GoogleAuthUtil.requestGoogleAccountsAccess(this);
    Log.i(TAG, "googleAccountAccessGranted: " + googleAccountAccessGranted);
}

// exception handler after calling method above
private void handleAuthResult(Throwable e)
{
    if (e instanceof UserRecoverableAuthException)
    {
        UserRecoverableAuthException authException = (UserRecoverableAuthException) e;
        startActivityForResult(authException.getIntent(), AUTH_PERMISSION_REQUEST);
    }
    else
    {
        Log.e(TAG, "Cannot request Google Account Access", e);
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == AUTH_PERMISSION_REQUEST)
    {
        Log.i(TAG, "Google Auth Permission Result");

        if (resultCode == Activity.RESULT_CANCELED)
        {
            Log.w(TAG, "User Cancelled Play Services Auth Request.")
        }
        else if (resultCode == Activity.RESULT_OK)
        {
            Log.d(TAG, "User accepted Play Services Auth Request.");
            // call the following line again on a background thread. the call now returns a boolean instead of throwing an exception
            //  googleAccountAccessGranted = GoogleAuthUtil.requestGoogleAccountsAccess(this);
        }
    }
}

Немного странно, почему Google решился на эту "архитектуру". Почему бы не вернуть задачу и т. д. Но так вы заработаете.

Конечно, этот код нуждается в надлежащей обработке исключений, которую я не учел для удобочитаемости.

person AndyB    schedule 04.10.2018