Как получить основной адрес электронной почты устройства Android

412

Как получить основной адрес электронной почты Android (или список адресов электронной почты)?

Насколько я понимаю, в OS 2.0+ есть поддержка нескольких адресов электронной почты, но ниже 2.0 вы можете иметь только один адрес электронной почты на устройство.

Брэндон О'Рурк
источник
Вы говорите о получении адреса электронной почты контактов?
Остин Махони
1
Нет, основной адрес электронной почты устройства.
Брэндон О'Рурк
Есть один или несколько адресов электронной почты, связанных с устройством Android, верно? Это то, что я хочу.
Брэндон О'Рурк
2
@ BrandonO'Rourke Вы подразумеваете «основной адрес электронной почты устройства» как адрес, связанный с Android Market? Потому что есть разница между идентификатором Gmail, связанным с Android Market и другими электронными письмами. Посмотрите на этот вопрос stackoverflow.com/questions/10606976/…
Гаурав Агарвал

Ответы:

749

Есть несколько способов сделать это, показанные ниже.

В качестве дружеского предупреждения будьте внимательны и откровенны с пользователем при работе с учетной записью, профилем и контактными данными. Если вы неправильно используете адрес электронной почты пользователя или другую личную информацию, могут произойти плохие вещи.

Способ А. Использование AccountManager (уровень API 5+)

Вы можете использовать AccountManager.getAccountsили, AccountManager.getAccountsByTypeчтобы получить список всех имен учетных записей на устройстве. К счастью, для определенных типов учетных записей (в том числе com.google), имена учетных записей являются адресами электронной почты. Пример фрагмента ниже.

Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
Account[] accounts = AccountManager.get(context).getAccounts();
for (Account account : accounts) {
    if (emailPattern.matcher(account.name).matches()) {
        String possibleEmail = account.name;
        ...
    }
}

Обратите внимание, что для этого требуется GET_ACCOUNTSразрешение:

<uses-permission android:name="android.permission.GET_ACCOUNTS" />

Подробнее об использовании AccountManagerможно найти в образце кода Contact Manager в SDK.

Способ Б. Использование ContactsContract.Profile (уровень API 14+).

Начиная с Android 4.0 (Ice Cream Sandwich), вы можете получить адреса электронной почты пользователя, зайдя в его профиль. Доступ к профилю пользователя немного тяжеловесен, поскольку требует двух разрешений (подробнее об этом ниже), но адреса электронной почты являются довольно конфиденциальными данными, поэтому это цена входного билета.

Ниже приведен полный пример, который использует CursorLoaderдля получения строк данных профиля, содержащих адреса электронной почты.

public class ExampleActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getLoaderManager().initLoader(0, null, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle arguments) {
        return new CursorLoader(this,
                // Retrieve data rows for the device user's 'profile' contact.
                Uri.withAppendedPath(
                        ContactsContract.Profile.CONTENT_URI,
                        ContactsContract.Contacts.Data.CONTENT_DIRECTORY),
                ProfileQuery.PROJECTION,

                // Select only email addresses.
                ContactsContract.Contacts.Data.MIMETYPE + " = ?",
                new String[]{ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE},

                // Show primary email addresses first. Note that there won't be
                // a primary email address if the user hasn't specified one.
                ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        List<String> emails = new ArrayList<String>();
        cursor.moveToFirst();
        while (!cursor.isAfterLast()) {
            emails.add(cursor.getString(ProfileQuery.ADDRESS));
            // Potentially filter on ProfileQuery.IS_PRIMARY
            cursor.moveToNext();
        }

        ...
    }

    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {
    }

    private interface ProfileQuery {
        String[] PROJECTION = {
                ContactsContract.CommonDataKinds.Email.ADDRESS,
                ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
        };

        int ADDRESS = 0;
        int IS_PRIMARY = 1;
    }
}

Это требует как READ_PROFILEи READ_CONTACTSразрешения:

<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
Роман Нурик
источник
3
у меня есть похожий вопрос, используя ваш код, я могу получить все идентификаторы Gmail, связанные с моим телефоном, но я хочу основной. Я нашел одно решение, например, когда мы добавляем больше почтовых идентификаторов для синхронизации с телефоном, оно попадает в стек, если я получаю 0-ю позицию com.google id, я получаю основное, потому что оно входит первым и получает 0-ю позицию в стеке. , Вот мой некоторый код Account [] accounts = AccountManager.get (this) .getAccountsByType ("com.google"); String myEmailid = accounts [0] .toString (); Log.d («Мой почтовый идентификатор, который я хочу», myEmailid); я знаю, что это не правильный путь.
ПиюшМишра
59
Профильный метод плохо испорчен (на мой взгляд). Приложение, которое хочет / нуждается в моей электронной почте, не имеет большого значения по сравнению с приложением, которое хочет прочитать все мои контакты, но вы сделали это так, что им обоим требуются одинаковые разрешения. Поэтому, как пользователь, я не могу отличить приложение, которое будет читать мою электронную почту, и приложение, которое будет читать мои 500+ контактов. Это очень реальная, практическая проблема, так как растет число приложений, которые злоупотребляют вашими контактами!
Том
3
@Muzikant Это ни в коем случае не официальное заявление, но вряд ли что-то изменится. Сказав это, «правильный» способ доступа к адресам электронной почты пользователя - это метод B. Это более «официальный» способ, и тот факт, что за некоторыми тяжелыми разрешениями следует указывать чувствительность, с которой вам следует обращаться к таким данным.
Роман Нурик
15
Я согласен с @Tom по этому вопросу. Запрашивать разрешение на получение данных всех контактов на телефоне только по имени и фамилии пользователя просто смешно.
Tasomaniac
3
Метод B не работает для меня в Android 4.4, копируя весь пример кода. cursor.isAfterLast()всегда возвращает истину. Есть идеи?
cprcrack
55

Это может быть полезно для других:

Использование AccountPicker для получения адреса электронной почты пользователя без каких-либо глобальных разрешений, а также позволяет пользователю быть в курсе и авторизовать или отменить процесс.

Хорхе Севаллос
источник
1
Это очень полезный ответ, я думаю, что это должен быть предпочтительный вариант, так как основной адрес электронной почты обычно означает учетную запись Google, которая, в свою очередь, будет у вас в сочетании с Google Play
Alex.F
@ Alex.F Работает ли это для версий Android после / от Marshmellow?
Ишвар
27

Я бы использовал Android AccountPicker , представленный в ICS.

Intent googlePicker = AccountPicker.newChooseAccountIntent(null, null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, null, null, null, null);
startActivityForResult(googlePicker, REQUEST_CODE);

А затем дождитесь результата:

protected void onActivityResult(final int requestCode, final int resultCode,
                                final Intent data) {
    if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
        String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
    }
}
SeBsZ
источник
2
Обратите внимание, что для этого требуется использование play-сервисов, и в некоторых случаях будет отображаться диалоговое окно, в котором пользователю нужно будет выбрать аккаунт.
Android-разработчик
Использование AccountManager.newChooseAccountIntent () выполняет ту же работу и не требует библиотеки play-services.
Денис
Приводит ли это всплывающее окно к пользователю для аутентификации учетной записи в контексте последней версии Android? Если да, как я могу обойти это для устройства, имеющего только одну учетную запись?
Ишвар
14
public String getUsername() {
    AccountManager manager = AccountManager.get(this);
    Account[] accounts = manager.getAccountsByType("com.google");
    List<String> possibleEmails = new LinkedList<String>();

    for (Account account : accounts) {
        // TODO: Check possibleEmail against an email regex or treat
        // account.name as an email address only for certain account.type values.
        possibleEmails.add(account.name);
    }

    if (!possibleEmails.isEmpty() && possibleEmails.get(0) != null) {
        String email = possibleEmails.get(0);
        String[] parts = email.split("@");

        if (parts.length > 1)
            return parts[0];
    }
    return null;
}
Афзаал Ифтихар
источник
Хороший и простой метод Спасибо :)
Talha Q
2
Обратите внимание, что это требует android.permission.GET_ACCOUNTS, которое определено как «опасное» разрешение (требуется запрос времени выполнения): developer.android.com/reference/android/…
SagiLow
@SagiLow Как ты справился с этим? Я не хочу просить у пользователя другое разрешение, просто чтобы ему лень вводить свой адрес электронной почты :)
базе кода
1
@ на основе кода я не ... это не возможно, насколько я знаю.
SagiLow
2
manager.getAccountsByType ( "com.google"); не работает с более поздними версиями Android.
powder366
8

Существует Android API, который позволяет пользователю выбирать свой адрес электронной почты без необходимости разрешения. Взгляните на: https://developers.google.com/identity/smartlock-passwords/android/retrieve-hints

HintRequest hintRequest = new HintRequest.Builder()
        .setHintPickerConfig(new CredentialPickerConfig.Builder()
                .setShowCancelButton(true)
                .build())
        .setEmailAddressIdentifierSupported(true)
        .setAccountTypes(IdentityProviders.GOOGLE)
        .build();

PendingIntent intent = mCredentialsClient.getHintPickerIntent(hintRequest);
try {
    startIntentSenderForResult(intent.getIntentSender(), RC_HINT, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
    Log.e(TAG, "Could not start hint picker Intent", e);
}

Это покажет средство выбора, где пользователь может выбрать адрес электронной почты. Результат будет доставлен вonActivityResult()

Wirling
источник
Я могу подтвердить, что смог использовать это, спасибо за единственный рабочий ответ, который я нашел
csga5000
Только рабочий раствор, благодаря wirling
Zulqarnain
7

К сожалению, принятый ответ не работает.

Я опаздываю, но вот решение для внутреннего приложения электронной почты Android, если контент не изменен поставщиком:

Uri EMAIL_ACCOUNTS_DATABASE_CONTENT_URI = 
              Uri.parse("content://com.android.email.provider/account");

public ArrayList<String> GET_EMAIL_ADDRESSES ()
{
    ArrayList<String> names = new ArrayList<String>();
    ContentResolver cr      = m_context.getContentResolver();
    Cursor cursor           = cr.query(EMAIL_ACCOUNTS_DATABASE_CONTENT_URI ,null, 
                             null, null, null);

    if (cursor == null) {
        Log.e("TEST", "Cannot access email accounts database");
        return null;
    }

    if (cursor.getCount() <= 0) {
        Log.e("TEST", "No accounts");
        return null;
    }

    while (cursor.moveToNext()) {
        names.add(cursor.getString(cursor.getColumnIndex("emailAddress")));
        Log.i("TEST", cursor.getString(cursor.getColumnIndex("emailAddress")));
    }
    return names;
}
День Бурака
источник
2

Используйте этот метод:

 public String getUserEmail() {
    AccountManager manager = AccountManager.get(App.getInstance());
    Account[] accounts = manager.getAccountsByType("com.google");
    List<String> possibleEmails = new LinkedList<>();
    for (Account account : accounts) {
        possibleEmails.add(account.name);
    }
    if (!possibleEmails.isEmpty() && possibleEmails.get(0) != null) {
        return possibleEmails.get(0);
    }
    return "";
}

Обратите внимание, что для этого требуется GET_ACCOUNTSразрешение:

<uses-permission android:name="android.permission.GET_ACCOUNTS" />

Затем:

editTextEmailAddress.setText(getUserEmail());
Иман Мараши
источник
Похоже, что это возвращает только учетные записи, связанные с текущим приложением - поэтому я получаю «нет» в тестировании
csga5000
manager.getAccountsByType ("com.google") не работает в более поздних версиях Android. А что такое App.getInstance ()?
powder366
0

Android GET_ACCOUNTSнедавно заблокировался, поэтому некоторые ответы у меня не сработали. Я получил это работает на Android 7.0 с оговоркой, что ваши пользователи должны вынести диалог разрешения.

AndroidManifest.xml

<uses-permission android:name="android.permission.GET_ACCOUNTS"/>

MainActivity.java

package com.example.patrick.app2;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.accounts.AccountManager;
import android.accounts.Account;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.*;

public class MainActivity extends AppCompatActivity {

    final static int requestcode = 4; //arbitrary constant less than 2^16

    private static String getEmailId(Context context) {
        AccountManager accountManager = AccountManager.get(context);
        Account[] accounts = accountManager.getAccountsByType("com.google");
        Account account;
        if (accounts.length > 0) {
            account = accounts[0];
        } else {
            return "length is zero";
        }
        return account.name;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case requestcode:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    String emailAddr = getEmailId(getApplicationContext());
                    ShowMessage(emailAddr);

                } else {
                    ShowMessage("Permission Denied");
                }
        }
    }

    public void ShowMessage(String email)
    {
        AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create();
        alertDialog.setTitle("Alert");
        alertDialog.setMessage(email);
        alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
        alertDialog.show();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Context context = getApplicationContext();

        if ( ContextCompat.checkSelfPermission( context, android.Manifest.permission.GET_ACCOUNTS )
                != PackageManager.PERMISSION_GRANTED )
        {
            ActivityCompat.requestPermissions( this, new String[]
                            {  android.Manifest.permission.GET_ACCOUNTS  },requestcode );
        }
        else
        {
            String possibleEmail = getEmailId(getApplicationContext());
            ShowMessage(possibleEmail);
        }
    }
}
Патрик
источник
Это не отличается от других ответов, и похоже, что они не работают для меня - по-видимому, потому что в более новых версиях Android это только возвращает учетные записи, связанные с приложением, и больше не требует разрешения.
csga5000
0

Работа в операционной системе MarshMallow

    btn_click=(Button) findViewById(R.id.btn_click);

    btn_click.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View arg0)
        {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
            {
                int permissionCheck = ContextCompat.checkSelfPermission(PermissionActivity.this,
                        android.Manifest.permission.CAMERA);
                if (permissionCheck == PackageManager.PERMISSION_GRANTED)
                {
                    //showing dialog to select image
                    String possibleEmail=null;

                     Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
                     Account[] accounts = AccountManager.get(PermissionActivity.this).getAccounts();
                     for (Account account : accounts) {
                         if (emailPattern.matcher(account.name).matches()) {
                             possibleEmail = account.name;
                             Log.e("keshav","possibleEmail"+possibleEmail);
                         }
                     }

                    Log.e("keshav","possibleEmail gjhh->"+possibleEmail);
                    Log.e("permission", "granted Marshmallow O/S");

                } else {                        ActivityCompat.requestPermissions(PermissionActivity.this,
                            new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE,
                                    android.Manifest.permission.READ_PHONE_STATE,
                                    Manifest.permission.GET_ACCOUNTS,
                                    android.Manifest.permission.CAMERA}, 1);
                }
            } else {
// Lower then Marshmallow

                    String possibleEmail=null;

                     Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
                     Account[] accounts = AccountManager.get(PermissionActivity.this).getAccounts();
                     for (Account account : accounts) {
                         if (emailPattern.matcher(account.name).matches()) {
                             possibleEmail = account.name;
                             Log.e("keshav","possibleEmail"+possibleEmail);
                     }

                    Log.e("keshav","possibleEmail gjhh->"+possibleEmail);


            }
        }
    });
Кешав Гера
источник
<использует-разрешение android: name = "android.permission.GET_ACCOUNTS" />
Кешав Гера
1
Ответы на получение учетных записей не сработали для меня (верните 0 учетных записей) - и я могу подтвердить, что вызов кода в обратном вызове кнопки не имел значения.
csga5000
Этот Кодекс работает, но в последнее время у меня есть проблема со временем, поэтому, пожалуйста, проверьте нашу сторону
Кешав Гера
0

Добавьте эту единственную строку в манифест ( для разрешения )

<uses-permission android:name="android.permission.GET_ACCOUNTS" />

Затем вставьте этот код в вашу деятельность

private ArrayList<String> getPrimaryMailId() {
    ArrayList<String> accountsList = new ArrayList<String>();
    try {
        Account[] accounts = AccountManager.get(this).getAccountsByType("com.google");
        for (Account account : accounts) {
            accountsList.add(account.name);
            Log.e("GetPrimaryMailId ", account.name);
        }
    } catch (Exception e) {
        Log.e("GetPrimaryMailId", " Exception : " + e);
    }
    return accountsList;
}
Agilanbu
источник