Comment obtenir l'adresse e-mail principale de l'appareil Android

412

Comment obtenir l'adresse e-mail principale d'Android (ou une liste d'adresses e-mail)?

Je crois comprendre que sur OS 2.0+, il existe un support pour plusieurs adresses e-mail, mais en dessous de 2.0, vous ne pouvez avoir qu'une seule adresse e-mail par appareil.

Brandon O'Rourke
la source
Parlez-vous de récupérer une adresse e-mail de contacts?
Austyn Mahoney
1
Non, l'adresse e-mail principale de l'appareil.
Brandon O'Rourke
Il y a une ou plusieurs adresses e-mail associées à un appareil Android, n'est-ce pas? Voilà ce que je voudrais.
Brandon O'Rourke
2
@ BrandonO'Rourke Voulez-vous dire "l'adresse e-mail principale de l'appareil" comme celle associée à l'Android Market? Parce qu'il existe une différence entre l'identifiant gmail associé à l'Android Market et les autres e-mails. Jetez un œil à cette question stackoverflow.com/questions/10606976/…
Gaurav Agarwal

Réponses:

749

Il existe plusieurs façons de procéder, indiquées ci-dessous.

Comme avertissement amical, soyez prudent et direct envers l'utilisateur lorsqu'il traite des données de compte, de profil et de contact. Si vous abusez de l'adresse e-mail d'un utilisateur ou d'autres informations personnelles, de mauvaises choses peuvent se produire.

Méthode A: utiliser AccountManager (API niveau 5+)

Vous pouvez utiliser AccountManager.getAccountsou AccountManager.getAccountsByTypepour obtenir une liste de tous les noms de compte sur l'appareil. Heureusement, pour certains types de comptes (y compris com.google), les noms de compte sont des adresses e-mail. Exemple d'extrait ci-dessous.

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;
        ...
    }
}

Notez que cela nécessite l' GET_ACCOUNTSautorisation:

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

Pour plus d'informations sur l'utilisation, AccountManagerconsultez l' exemple de code Contact Manager dans le SDK.

Méthode B: utilisez ContactsContract.Profile (API niveau 14+)

Depuis Android 4.0 (Ice Cream Sandwich), vous pouvez obtenir les adresses e-mail de l'utilisateur en accédant à son profil. L'accès au profil utilisateur est un peu lourd car il nécessite deux autorisations (plus d'informations ci-dessous), mais les adresses e-mail sont des données assez sensibles, c'est donc le prix d'admission.

Voici un exemple complet qui utilise un CursorLoaderpour récupérer les lignes de données de profil contenant des adresses e-mail.

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;
    }
}

Cela nécessite à la fois les autorisations READ_PROFILEet READ_CONTACTS:

<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
Roman Nurik
la source
3
j'ai une question similaire en utilisant votre code, je peux obtenir tous les identifiants gmail associés à mon téléphone, mais je veux le principal. J'ai trouvé une solution comme lorsque nous ajoutons plus d'identifiants de messagerie pour synchroniser avec le téléphone, ils entrent dans une pile si j'obtiens la 0e position id com.google, j'obtiens la principale car elle entre en premier et acquiert la 0e position dans une pile . Voici mon code Account [] accounts = AccountManager.get (this) .getAccountsByType ("com.google"); String myEmailid = accounts [0] .toString (); Log.d ("Mon identifiant e-mail que je veux", myEmailid); je sais que ce n'est pas la bonne façon.
PiyushMishra
59
La méthode de profil est gravement défectueuse (à mon avis). Une application qui veut / a besoin de mon e-mail n'est pas un gros problème par rapport à une application qui veut lire tous mes contacts, mais vous avez fait en sorte qu'ils nécessitent tous les deux les mêmes autorisations. Donc, en tant qu'utilisateur, je ne peux pas faire la différence entre une application qui va lire mes e-mails et une application qui va lire mes 500+ contacts. Il s'agit d'un problème très réel et pratique, car le nombre d'applications qui abusent de vos contacts augmente!
Tom
3
@Muzikant Ce n'est en aucun cas une déclaration officielle, mais c'est quelque chose qui est peu susceptible de changer. Cela dit, la méthode "correcte" pour accéder aux adresses e-mail d'un utilisateur est la méthode B. C'est plus "officiel" et le fait qu'il se trouve derrière certaines autorisations importantes devrait indiquer la sensibilité avec laquelle vous devez aborder ces données.
Roman Nurik
15
Je suis d'accord avec @Tom à ce sujet. Demander la permission pour les données de tous les contacts sur le téléphone juste pour le prénom et le nom de l'utilisateur est ridicule.
tasomaniac
3
La méthode B ne fonctionne pas pour moi dans Android 4.4 en copiant tout le code d'exemple. cursor.isAfterLast()renvoie toujours vrai. Une idée?
cprcrack
55

Cela pourrait être utile à d'autres:

Utiliser AccountPicker pour obtenir l'adresse e-mail de l'utilisateur sans aucune autorisation globale et permettre à l'utilisateur d'être informé et d'autoriser ou d'annuler le processus.

Jorge Cevallos
la source
1
Ceci est une réponse très utile, je pense que cela devrait être l'option préférée car l'e-mail principal signifie généralement le compte Google, que vous aurez à son tour en collaboration avec Google Play
Alex.F
@ Alex.F Est-ce que cela fonctionne pour les versions Android après / de marshmellow?
Eswar
27

J'utiliserais AccountPicker d'Android , introduit dans ICS.

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

Et puis attendez le résultat:

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
la source
2
Notez qu'il vous oblige à utiliser les services de jeu, et qu'il affichera une boîte de dialogue dans certains cas, que l'utilisateur devra choisir le compte.
développeur Android
L'utilisation de AccountManager.newChooseAccountIntent () fait le même travail et ne nécessite pas la bibliothèque play-services.
Denis
Est-ce que cela ouvre un pop-up à l'utilisateur pour l'authentification du compte dans le contexte de la dernière version d'Android? Si oui, comment puis-je contourner cela pour un appareil ayant un seul compte?
Eswar
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;
}
Afzaal Iftikhar
la source
Méthode agréable et facile Merci :)
Talha Q
2
Notez que cela nécessite android.permission.GET_ACCOUNTS, qui est défini comme une autorisation «dangereuse» (nécessite une demande d'exécution): developer.android.com/reference/android/…
SagiLow
@SagiLow Comment avez-vous géré cela? Je ne veux pas demander à l'utilisateur, pour une autre autorisation, juste de le rendre paresseux pour entrer son adresse e-mail :)
basé sur
1
@codebased Je ne l'ai pas fait ... ce n'est pas possible pour autant que je sache.
SagiLow
2
manager.getAccountsByType ("com.google"); ne fonctionne pas avec les versions ultérieures d'Android.
powder366
8

Il existe une API Android qui permet à l'utilisateur de sélectionner son adresse e-mail sans avoir besoin d'une autorisation. Jetez un œil à: 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);
}

Cela montrera un sélecteur où l'utilisateur peut sélectionner une adresse e-mail. Le résultat sera livré enonActivityResult()

Tourbillonnant
la source
Je peux confirmer que j'ai pu l'utiliser, merci pour la seule réponse de travail que j'ai trouvée
csga5000
La seule solution de travail, merci wirling
Zulqarnain
7

La réponse malheureusement acceptée ne fonctionne pas.

Je suis en retard, mais voici la solution pour l'application de messagerie Android interne, sauf si l'URI du contenu est modifié par le fournisseur:

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;
}
Journée Burak
la source
2

Utilisez cette méthode:

 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 "";
}

Notez que cela nécessite l' GET_ACCOUNTSautorisation:

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

Alors:

editTextEmailAddress.setText(getUserEmail());
Iman Marashi
la source
Cela semble ne renvoyer que les comptes associés à l'application actuelle - donc j'obtiens «aucun» lors des tests
csga5000
manager.getAccountsByType ("com.google") ne fonctionne pas dans les versions ultérieures d'Android. Et d'où vient App.getInstance ()?
powder366
0

Android s'est verrouillé GET_ACCOUNTSrécemment, donc certaines des réponses n'ont pas fonctionné pour moi. J'ai obtenu que cela fonctionne sur Android 7.0 avec la mise en garde que vos utilisateurs doivent supporter une boîte de dialogue d'autorisation.

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);
        }
    }
}
patrick
la source
Cela ne diffère pas des autres réponses et cela ne fonctionne pas pour moi - apparemment parce que dans les nouvelles versions d'Android, cela ne renvoie que les comptes associés à l'application et ne nécessite plus l'autorisation.
csga5000
0

Travailler dans le système d'exploitation 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);


            }
        }
    });
Keshav Gera
la source
<uses-permission android: name = "android.permission.GET_ACCOUNTS" />
Keshav Gera
1
Les réponses Obtenir des comptes n'ont pas fonctionné pour moi (retourner 0 compte) - et je peux confirmer que l'appel du code dans un rappel de bouton n'a fait aucune différence.
csga5000
Ce code fonctionne, mais récemment, j'ai un problème de temps, veuillez donc vérifier de notre côté
Keshav Gera
0

Ajouter cette seule ligne dans le manifeste ( pour autorisation )

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

Collez ensuite ce code dans votre activité

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
la source