Cómo obtener la dirección de correo electrónico principal del dispositivo Android

412

¿Cómo se obtiene la dirección de correo electrónico principal de Android (o una lista de direcciones de correo electrónico)?

Tengo entendido que en OS 2.0+ hay soporte para múltiples direcciones de correo electrónico, pero por debajo de 2.0 solo puede tener una dirección de correo electrónico por dispositivo.

Brandon O'Rourke
fuente
¿Estás hablando de recuperar una dirección de correo electrónico de contactos?
Austyn Mahoney
1
No, la dirección de correo electrónico principal del dispositivo.
Brandon O'Rourke
Hay una o más direcciones de correo electrónico asociadas con un dispositivo Android, ¿verdad? Eso es lo que quiero.
Brandon O'Rourke
2
@ BrandonO'Rourke ¿Se refiere a "la dirección de correo electrónico principal del dispositivo" como la asociada con Android Market? Porque hay una diferencia entre la identificación de gmail asociada con Android Market y otros correos electrónicos. Eche un vistazo a esta pregunta stackoverflow.com/questions/10606976/…
Gaurav Agarwal

Respuestas:

749

Hay varias formas de hacer esto, que se muestran a continuación.

Como advertencia amistosa, tenga cuidado y sea sincero con el usuario cuando maneje datos de cuenta, perfil y contacto. Si utiliza indebidamente la dirección de correo electrónico de un usuario u otra información personal, pueden ocurrir cosas malas.

Método A: usar AccountManager (API nivel 5+)

Puede usar AccountManager.getAccountsu AccountManager.getAccountsByTypeobtener una lista de todos los nombres de cuenta en el dispositivo. Afortunadamente, para ciertos tipos de cuenta (incluidos com.google), los nombres de las cuentas son direcciones de correo electrónico. Fragmento de ejemplo a continuación.

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

Tenga en cuenta que esto requiere el GET_ACCOUNTSpermiso:

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

AccountManagerPuede encontrar más información sobre el uso en el código de muestra de Contact Manager en el SDK.

Método B: usar ContactsContract.Profile (API nivel 14+)

A partir de Android 4.0 (Ice Cream Sandwich), puede obtener las direcciones de correo electrónico del usuario accediendo a su perfil. Acceder al perfil de usuario es un poco pesado, ya que requiere dos permisos (más sobre eso a continuación), pero las direcciones de correo electrónico son datos bastante confidenciales, por lo que este es el precio de admisión.

A continuación se muestra un ejemplo completo que utiliza un CursorLoaderpara recuperar filas de datos de perfil que contienen direcciones de correo electrónico.

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

Esto requiere los permisos READ_PROFILEy READ_CONTACTS:

<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
Nurik romano
fuente
3
Tengo una pregunta similar al usar su código. Puedo obtener todos los ID de Gmail asociados con mi teléfono, pero quiero el principal. Encontré una solución como cuando agregamos más ID de correo para sincronizar con el teléfono, viene en una pila si obtengo la posición 0 com.google id, obtengo la primaria porque ingresa primero y adquiere la posición 0 en una pila . Aquí está mi código Account [] accounts = AccountManager.get (this) .getAccountsByType ("com.google"); Cadena myEmailid = cuentas [0] .toString (); Log.d ("Mi ID de correo electrónico que quiero", myEmailid); Sé que no es la forma correcta.
PiyushMishra
59
El método de perfil es muy defectuoso (en mi opinión). Una aplicación que quiere / necesita mi correo electrónico no es un gran problema en comparación con una aplicación que quiere leer todos mis contactos, pero lo ha hecho para que ambos requieran los mismos permisos. Como usuario, no puedo distinguir la diferencia entre una aplicación que leerá mi correo electrónico y una aplicación que leerá mis más de 500 contactos. ¡Este es un problema muy real y práctico ya que la cantidad de aplicaciones que abusan de sus contactos está creciendo!
Tom
3
@Muzikant De ninguna manera es una declaración oficial, pero es algo que es poco probable que cambie. Dicho esto, la forma "correcta" de acceder a las direcciones de correo electrónico de un usuario es el Método B. Eso es más "oficial" y el hecho de que esté detrás de algunos permisos pesados ​​debería indicar la sensibilidad con la que debe abordar dichos datos.
Roman Nurik
15
Estoy de acuerdo con @Tom en esto. Pedir permiso para los datos de todos los contactos en el teléfono solo para el nombre y apellido del usuario es ridículo.
tasomaniac
3
El método B no me funciona en Android 4.4 copiando todo el código de ejemplo. cursor.isAfterLast()siempre devuelve verdadero. ¿Alguna idea?
cprcrack
55

Esto podría ser útil para otros:

Usar AccountPicker para obtener la dirección de correo electrónico del usuario sin ningún permiso global, y permitir que el usuario conozca y autorice o cancele el proceso.

Jorge Cevallos
fuente
1
Esta es una respuesta muy útil, creo que esta debería ser la opción preferida ya que el correo electrónico principal generalmente significa la cuenta de Google, que a su vez tendrá junto con Google Play
Alex.F
@ Alex.F ¿Funciona esto para las versiones de Android después / de marshmellow?
Eswar
27

Usaría AccountPicker de Android , introducido en ICS.

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

Y luego espera el resultado:

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
fuente
2
Tenga en cuenta que requiere que use servicios de reproducción y que, en algunos casos, mostrará un cuadro de diálogo en el que el usuario deberá elegir la cuenta.
Desarrollador de Android
El uso de AccountManager.newChooseAccountIntent () hace el mismo trabajo y no requiere la biblioteca de servicios de reproducción.
Denis
¿Esto arroja una ventana emergente al usuario para la autenticación de la cuenta en el contexto de la última versión de Android? En caso afirmativo, ¿cómo puedo evitar eso para un dispositivo que solo tiene una cuenta?
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
fuente
Método agradable y fácil Gracias :)
Talha Q
2
Tenga en cuenta que esto requiere android.permission.GET_ACCOUNTS, que se define como permiso 'peligroso' (requiere solicitud de tiempo de ejecución): developer.android.com/reference/android/…
SagiLow
@SagiLow ¿Cómo manejaste esto? No quiero pedirle al usuario, para otro permiso, solo para hacerlo flojo para ingresar su dirección de correo electrónico :)
basado en código
1
@codebased No lo hice ... por lo que sé, no es posible.
SagiLow
2
manager.getAccountsByType ("com.google"); no funciona con versiones posteriores de Android.
powder366
8

Hay una API de Android que permite al usuario seleccionar su dirección de correo electrónico sin la necesidad de un permiso. Echa un vistazo a: 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);
}

Esto mostrará un selector donde el usuario puede seleccionar una dirección de correo electrónico. El resultado será entregado enonActivityResult()

Wirling
fuente
Puedo confirmar que pude usar esto, gracias por la única respuesta que he encontrado
csga5000
La única solución de trabajo, gracias girando
Zulqarnain
7

La respuesta tristemente aceptada no está funcionando.

Llego tarde, pero aquí está la solución para la aplicación interna de correo electrónico de Android a menos que el proveedor cambie la uri de contenido:

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;
}
Día de Burak
fuente
2

Usa este método:

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

Tenga en cuenta que esto requiere el GET_ACCOUNTSpermiso:

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

Entonces:

editTextEmailAddress.setText(getUserEmail());
Iman Marashi
fuente
Esto parece solo devolver cuentas asociadas con la aplicación actual, por lo que obtengo "ninguna" en las pruebas
Csga5000
manager.getAccountsByType ("com.google") no funciona en versiones posteriores de Android. ¿Y de qué es App.getInstance ()?
polvo366
0

Android se bloqueó GET_ACCOUNTSrecientemente, por lo que algunas de las respuestas no me funcionaron. Esto funciona en Android 7.0 con la advertencia de que sus usuarios tienen que soportar un diálogo de permiso.

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);
        }
    }
}
Patricio
fuente
Esto no difiere de otras respuestas y parece que no funciona para mí, aparentemente porque en las versiones más recientes de Android esto solo devuelve cuentas asociadas con la aplicación y ya no requiere el permiso.
csga5000
0

Trabajando en el sistema operativo 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
fuente
<usos-permiso android: name = "android.permission.GET_ACCOUNTS" />
Keshav Gera
1
Obtener respuestas de cuentas no me ha funcionado (devolver 0 cuentas), y puedo confirmar que llamar al código en una devolución de llamada de botón no hizo ninguna diferencia.
csga5000
Este Código está funcionando, pero recientemente tengo un problema de tiempo, así que revise nuestro lado
Keshav Gera
0

Agregue esta línea única en manifiesto ( para permiso )

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

Luego pegue este código en su actividad

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
fuente