Як отримати основну електронну адресу пристрою Android


412

Як отримати основну електронну адресу Android (або список адрес електронної пошти)?

Я розумію, що в OS 2.0+ є підтримка декількох адрес електронної пошти, але нижче 2.0 ви можете мати лише одну адресу електронної пошти на кожен пристрій.


Ви говорите про отримання електронної адреси контактів?
Остін Махоні

1
Ні, основна адреса електронної пошти пристрою.
Брендон О'Рурк

Є одна чи кілька електронних адрес, пов’язаних із пристроєм Android, правда? Це я хотів би.
Брендон О'Рурк

2
@ BrandonO'Rourke Ви маєте на увазі "основну електронну адресу пристрою" як адресу, пов’язану з Android Market? Оскільки існує ідентифікатор gmail, пов’язаний із Android Market, та інші електронні листи. Подивіться на це питання stackoverflow.com/questions/10606976/…
Gaurav Agarwal

Відповіді:


749

Існує кілька способів зробити це, показані нижче.

Як доброзичливе попередження, будьте уважні та вперед до користувача, коли маєте справу з обліковими записами, профілями та контактними даними. Якщо ви неправильно використовуєте електронну адресу користувача чи іншу особисту інформацію, можуть статися погані речі.

Спосіб A: Використовуйте 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.

Спосіб B: Використовуйте ContactsContract.Profile (API рівня 14+)

Що стосується Android 4.0 (сендвіч з морозивом), ви можете отримати електронні адреси користувача, відкривши їх профіль. Доступ до профілю користувача трохи важкий, оскільки вимагає двох дозволів (докладніше про це нижче), але адреси електронної пошти є досить чутливими фрагментами даних, тому це ціна доступу.

Нижче наведено повний приклад, який використовує 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 [] account = AccountManager.get (this) .getAccountsByType ("com.google"); Рядок myEmailid = акаунти [0] .toString (); Log.d ("Мій ідентифікатор електронної пошти, який я хочу", myEmailid); я знаю, що це не правильний шлях.
ПіюшМішра

59
Метод профілю сильно хибно (на мою думку). Додаток, який хоче / потребує моєї електронної пошти, не є великою справою порівняно з додатком, який хоче прочитати всі мої контакти, але ви зробили це так, що вони обидва вимагають однакових дозволів. Отже, як користувач, я не можу визначити різницю між додатком, який збирається читати мою електронну пошту, і програмою, яка збирається читати мої 500+ контактів. Це дуже реальна, практична проблема, оскільки кількість програм, які зловживають вашими контактами, зростає!
Том

3
@Muzikant Це аж ніяк не офіційна заява, але це щось, що навряд чи зміниться. Сказавши це, "правильним" способом доступу до електронних адрес користувача є метод B. Це є більш "офіційним", а той факт, що він стоїть за деякими важкими дозволами, повинен вказувати на чутливість, з якою ви повинні підходити до таких даних.
Роман Нурік

15
Я згоден з @Tom щодо цього. Запитувати дозвіл на дані всіх контактів на телефоні лише на Ім'я та Прізвище користувача смішно.
тасоман

3
Спосіб B не працює для мене в Android 4.4, копіюючи весь приклад код. cursor.isAfterLast()завжди повертає правду. Будь-яка ідея?
cprcrack

55

Це може бути корисно для інших:

Використання AccountPicker для отримання електронної адреси користувача без будь-яких глобальних дозволів, а також дозволити користувачеві знати та авторизувати чи скасовувати процес.


1
Це дуже корисна відповідь, я думаю, що це має бути кращим варіантом, оскільки основний електронний лист зазвичай означає обліковий запис Google, що, у свою чергу, ви матимете спільно з Google Play
Alex.F

@ Alex.F Це працює для версій для Android після / від marshmellow?
Eswar

27

Я б використовував AccountPicker Android , представлений в 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);
    }
}

2
Зауважте, що він вимагає використання служб програвання, а в деяких випадках він відображатиме діалогове вікно, що користувачеві потрібно буде вибрати обліковий запис.
андроїд розробник

Використовуючи AccountManager.newChooseAccountIntent () виконайте таку ж роботу і не вимагає бібліотеки служб відтворення.
Денис

Чи це спричиняє користувачеві спливаюче вікно для перевірки автентичності облікового запису в контексті останньої версії 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
@codebased Я цього не зробив ... наскільки я знаю, це неможливо.
SagiLow

2
manager.getAccountsByType ("com.google"); не працює з пізнішими версіями Android.
порошок366

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()


Я можу підтвердити, що мені вдалося це використати, дякую за єдину знайдену робочу відповідь
csga5000

Єдине робоче рішення, завдяки ворлінгу
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 ()?
порошок366


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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.