Como obter o endereço de email principal do dispositivo Android

412

Como você obtém o endereço de email principal do Android (ou uma lista de endereços de email)?

Entendo que no OS 2.0+ há suporte para vários endereços de email, mas abaixo de 2.0 você pode ter apenas um endereço de email por dispositivo.

Brandon O'Rourke
fonte
Você está falando sobre recuperar um endereço de e-mail de contatos?
Austyn Mahoney
1
Não, o endereço de e-mail principal do dispositivo.
precisa saber é o seguinte
Há um ou mais endereços de email associados a um dispositivo Android, certo? Era o que eu queria.
precisa saber é o seguinte
2
@ BrandonO'Rourke Você quer dizer "o endereço de e-mail principal do dispositivo" como o associado ao Android Market? Porque existe uma diferença entre o ID do gmail associado ao Android Market e outros e-mails. Dê uma olhada nesta pergunta stackoverflow.com/questions/10606976/…
Gaurav Agarwal

Respostas:

749

Existem várias maneiras de fazer isso, mostradas abaixo.

Como um aviso amigável, tenha cuidado e seja franco com o usuário ao lidar com dados da conta, perfil e contato. Se você usar indevidamente o endereço de e-mail de um usuário ou outras informações pessoais, coisas ruins podem acontecer.

Método A: Use AccountManager (nível 5 da API)

Você pode usar AccountManager.getAccountsou AccountManager.getAccountsByTypeobter uma lista de todos os nomes de conta no dispositivo. Felizmente, para certos tipos de conta (inclusive com.google), os nomes das contas são endereços de email. Exemplo de snippet abaixo.

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

Observe que isso requer a GET_ACCOUNTSpermissão:

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

Mais informações sobre o uso AccountManagerpodem ser encontradas no código de exemplo do Contact Manager no SDK.

Método B: Use ContactsContract.Profile (nível de API 14 ou superior)

No Android 4.0 (Ice Cream Sandwich), você pode obter os endereços de e-mail do usuário acessando seu perfil. O acesso ao perfil do usuário é um pouco pesado, pois requer duas permissões (mais sobre isso abaixo), mas os endereços de email são dados bastante sensíveis, portanto esse é o preço da entrada.

Abaixo está um exemplo completo que usa a CursorLoaderpara recuperar linhas de dados de perfil que contêm endereços de email.

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

Isso requer as permissões READ_PROFILEe READ_CONTACTS:

<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
Roman Nurik
fonte
3
Eu tenho uma pergunta semelhante usando seu código, eu sou capaz de obter todos os IDs do Gmail associados ao meu telefone, mas eu quero o principal. Eu encontrei uma solução, à medida que adicionamos mais IDs de e-mail para sincronizar com o telefone, ele fica em uma pilha se estou recebendo a 0ª posição com.google id's, estou recebendo a principal porque entra primeiro e adquire a 0ª posição em uma pilha . Aqui estão alguns códigos Account [] accounts = AccountManager.get (this) .getAccountsByType ("com.google"); String myEmailid = contas [0] .toString (); Log.d ("Meu ID de e-mail que eu quero", myEmailid); Eu sei que não é o caminho correto.
PiyushMishra
59
O método de perfil é muito falho (na minha opinião). Um aplicativo que deseja / precisa do meu e-mail não é muito importante comparado a um aplicativo que deseja ler todos os meus contatos, mas você o fez para que ambos exijam as mesmas permissões. Portanto, como usuário, não sei dizer a diferença entre um aplicativo que lê meu email e um aplicativo que lê meus mais de 500 contatos. Esse é um problema prático muito real, pois o número de aplicativos que abusam de seus contatos está aumentando!
Tom
3
@Muzikant Não é de forma alguma uma declaração oficial, mas é algo que é improvável que mude. Dito isso, a maneira "correta" de acessar os endereços de e-mail de um usuário é o Método B. Isso é mais "oficial" e o fato de estar por trás de algumas permissões pesadas deve indicar a sensibilidade com a qual você deve abordar esses dados.
Roman Nurik
15
Eu concordo com @ Tom sobre isso. Pedir permissão para os dados de todos os contatos no telefone apenas para o Primeiro e o Sobrenome do usuário é ridículo.
tasomaniac
3
O método B não está funcionando para mim no Android 4.4, copiando todo o código de exemplo. cursor.isAfterLast()sempre retorna verdadeiro. Qualquer ideia?
Cprcrack
55

Isso pode ser útil para outras pessoas:

Usando o AccountPicker para obter o endereço de e-mail do usuário sem nenhuma permissão global e permitindo que o usuário esteja ciente e autorize ou cancele o processo.

Jorge Cevallos
fonte
1
Esta é uma resposta muito útil, eu acho que isso deve ser a opção preferida como primária e-mail geralmente significa a Conta do Google, que por sua vez terá em conjunto com o Google Play
Alex.F
@ Alex.F Isso funciona para versões do Android após / do marshmellow?
Eswar
27

Eu usaria o AccountPicker do Android , introduzido no ICS.

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

E aguarde o 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
fonte
2
Observe que ele requer o uso de serviços de reprodução e, em alguns casos, será exibida uma caixa de diálogo, indicando que o usuário precisará escolher a conta.
desenvolvedor android
O uso de AccountManager.newChooseAccountIntent () faz o mesmo trabalho e não requer a biblioteca de serviços de reprodução.
Denis
Isso abre uma janela para o usuário para autenticação da conta no contexto da versão mais recente do Android? Se sim, como ignorar isso para um dispositivo com apenas uma conta?
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
fonte
Agradável e método fácil Thanks :)
Talha Q
2
Observe isso requer android.permission.GET_ACCOUNTS, que definiu como permissão 'perigoso' (requer pedido de tempo de execução): developer.android.com/reference/android/...
SagiLow
@SagiLow Como você lidou com isso? Eu não quero perguntar usuário, para uma outra permissão, apenas para torná-lo preguiçoso para digitar seu endereço de e-mail :)
codebased
1
@ codebased eu não ... não é possível, tanto quanto eu sei.
SagiLow
2
manager.getAccountsByType ("com.google"); não funciona com versões posteriores do Android.
powder366
8

Existe uma API do Android que permite ao usuário selecionar seu endereço de e-mail sem a necessidade de permissão. Dê uma olhada em: 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);
}

Isso mostrará um seletor onde o usuário pode selecionar um endereço de email. O resultado será entregue emonActivityResult()

Wirling
fonte
Posso confirmar que eu era capaz de usar isso, obrigado pela resposta só trabalhando que eu encontrei
csga5000
A única solução de trabalho, graças girando
Zulqarnain
7

Infelizmente, a resposta aceita não está funcionando.

Estou atrasado, mas aqui está a solução para o aplicativo Android Email interno, a menos que a URL do conteúdo seja alterada pelo provedor:

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;
}
Dia de Burak
fonte
2

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

Observe que isso requer a GET_ACCOUNTSpermissão:

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

Então:

editTextEmailAddress.setText(getUserEmail());
Iman Marashi
fonte
Este parece única retorno contas associadas ao aplicativo atual - assim que eu conseguir "none" em testes
csga5000
manager.getAccountsByType ("com.google") não funciona em versões posteriores do Android. E do que é App.getInstance ()?
powder366
0

O Android foi bloqueado GET_ACCOUNTSrecentemente, então algumas das respostas não funcionaram para mim. Eu consegui isso trabalhando no Android 7.0 com a ressalva de que seus usuários precisam suportar uma caixa de diálogo de permissão.

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
fonte
Isso não difere de outras respostas e parece que essas não estão funcionando para mim - aparentemente porque nas versões mais recentes do Android isso só retorna contas associadas ao aplicativo e não requer mais permissão.
csga5000
0

Trabalhando no sistema operacional 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
fonte
<usa-permissão android: name = "android.permission.GET_ACCOUNTS" />
Keshav Gera
1
As respostas para obter contas não funcionaram para mim (retornar 0 contas) - e posso confirmar que chamar o código em um botão de retorno de chamada não fez diferença.
csga5000
Este código está funcionando, mas recentemente eu tenho tempo questão portanto, verifique o nosso lado
Keshav Gera
0

Adicione esta única linha no manifesto ( para permissão )

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

Em seguida, cole esse código em sua atividade

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
fonte