Cách nhận địa chỉ email chính của thiết bị Android


412

Làm thế nào để bạn có được địa chỉ e-mail chính của Android (hoặc danh sách các địa chỉ e-mail)?

Theo hiểu biết của tôi, trên OS 2.0 trở lên, có hỗ trợ cho nhiều địa chỉ email, nhưng dưới 2.0 bạn chỉ có thể có một địa chỉ email trên mỗi thiết bị.


Bạn đang nói về việc lấy một địa chỉ email liên lạc?
Austyn Mahoney

1
Không, địa chỉ e-mail chính của thiết bị.
Brandon O'Rourke

Có một hoặc nhiều địa chỉ email được liên kết với thiết bị Android phải không? Đó là những gì tôi muốn.
Brandon O'Rourke

2
@ BrandonO'Rourke Bạn có nghĩa là "Địa chỉ email chính của thiết bị" là địa chỉ được liên kết với Android Market? Bởi vì có sự khác biệt giữa id gmail được liên kết với Android Market và các email khác. Có một cái nhìn về câu hỏi này stackoverflow.com/questions/10606976/ từ
Gaurav Agarwal

Câu trả lời:


749

Có một số cách để làm điều này, được hiển thị dưới đây.

Như một cảnh báo thân thiện, hãy cẩn thận và thẳng thắn với người dùng khi giao dịch với tài khoản, hồ sơ và dữ liệu liên hệ. Nếu bạn sử dụng sai địa chỉ email của người dùng hoặc thông tin cá nhân khác, điều tồi tệ có thể xảy ra.

Phương pháp A: Sử dụng lý Tài khoản (cấp API 5 +)

Bạn có thể sử dụng AccountManager.getAccountshoặc AccountManager.getAccountsByTypeđể có danh sách tất cả tên tài khoản trên thiết bị. May mắn thay, đối với một số loại tài khoản nhất định (bao gồm com.google), tên tài khoản là địa chỉ email. Đoạn trích dưới đây.

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

Lưu ý rằng điều này cần có sự GET_ACCOUNTScho phép:

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

AccountManagerthể tìm hiểu thêm về cách sử dụng tại mã mẫu Trình quản lý liên hệ trong SDK.

Phương pháp B: Sử dụng Danh bạContract.Profile (API cấp 14+)

Kể từ Android 4.0 (Ice Cream Sandwich), bạn có thể nhận địa chỉ email của người dùng bằng cách truy cập hồ sơ của họ. Truy cập hồ sơ người dùng hơi nặng nề vì nó yêu cầu hai quyền (nhiều hơn ở bên dưới), nhưng địa chỉ email là những phần dữ liệu khá nhạy cảm, vì vậy đây là giá nhập học.

Dưới đây là một ví dụ đầy đủ sử dụng một CursorLoaderđể lấy các hàng dữ liệu hồ sơ có chứa địa chỉ 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;
    }
}

Điều này đòi hỏi cả quyền READ_PROFILEREAD_CONTACTSquyền:

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

3
Tôi có câu hỏi tương tự bằng cách sử dụng mã của bạn, tôi có thể nhận được tất cả id gmail được liên kết với điện thoại của mình nhưng tôi muốn mã chính. Tôi đã tìm thấy một giải pháp như khi chúng tôi thêm nhiều id mail để đồng bộ hóa với điện thoại, nó sẽ được xếp vào một ngăn xếp nếu tôi nhận được vị trí số 0 com.google id, tôi đang nhận được vị trí chính bởi vì nó nhập đầu tiên và có được vị trí số 0 trong một ngăn xếp . Đây là một số tài khoản mã của tôi [] Tài khoản = AccountManager.get (này) .getAccountsByType ("com.google"); Chuỗi myEmailid = tài khoản [0] .toString (); Log.d ("Id email của tôi mà tôi muốn", myEmailid); tôi biết nó không phải là cách chính xác.
PiyushMishra

59
Phương pháp hồ sơ là thiếu sót nghiêm trọng (theo ý kiến ​​của tôi). Một ứng dụng muốn / cần e-mail của tôi không phải là vấn đề lớn so với một ứng dụng muốn đọc tất cả các liên hệ của tôi, nhưng bạn đã làm nó để cả hai đều yêu cầu các quyền giống nhau. Vì vậy, với tư cách là người dùng, tôi không thể biết sự khác biệt giữa ứng dụng sẽ đọc e-mail của mình và ứng dụng sẽ đọc hơn 500 liên hệ của tôi. Đây là một vấn đề rất thực tế, thực tế vì số lượng ứng dụng lạm dụng danh bạ của bạn ngày càng tăng!
Tom

3
@Muzikant Đây không phải là một tuyên bố chính thức, nhưng đó là điều không thể thay đổi. Phải nói rằng, cách "truy cập" chính xác vào địa chỉ email của người dùng là Phương pháp B. Đó là "chính thức" hơn và thực tế là đằng sau một số quyền nặng sẽ chỉ ra độ nhạy mà bạn nên tiếp cận với dữ liệu đó.
Roman Nurik

15
Tôi đồng ý với @Tom về điều này. Xin phép dữ liệu của tất cả các số liên lạc trên điện thoại chỉ là Tên và Họ của người dùng là vô lý.
tasomaniac

3
Phương pháp B không hoạt động đối với tôi trong Android 4.4 sao chép tất cả mã ví dụ. cursor.isAfterLast()luôn luôn trả về đúng Bất kỳ ý tưởng?
cprcrack

55

Điều này có thể hữu ích cho những người khác:

Sử dụng AccountPicker để nhận địa chỉ email của người dùng mà không cần bất kỳ quyền toàn cầu nào và cho phép người dùng nhận biết và ủy quyền hoặc hủy quy trình.


1
Đây là một câu trả lời rất hữu ích, tôi nghĩ rằng đây nên là tùy chọn ưa thích vì Email chính thường có nghĩa là Tài khoản Google, đến lượt bạn sẽ có cùng với Google Play
Alex.F

@ Alex.F Điều này có hoạt động cho các phiên bản Android sau / từ marshmellow không?
Eswar

27

Tôi sẽ sử dụng AccountPicker của Android , được giới thiệu trong ICS.

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

Và sau đó chờ kết quả:

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
Lưu ý rằng nó yêu cầu bạn sử dụng các dịch vụ chơi và nó sẽ hiển thị hộp thoại trong một số trường hợp, người dùng sẽ cần chọn tài khoản.
nhà phát triển Android

Sử dụng AccountManager.newChooseAccountIntent () thực hiện cùng một công việc và không yêu cầu thư viện dịch vụ chơi.
Denis

Điều này có làm bật lên cho người dùng để xác thực tài khoản trong bối cảnh của phiên bản Android mới nhất không? Nếu có, làm thế nào để tôi bỏ qua điều đó cho một thiết bị chỉ có một tài khoản?
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;
}

Phương pháp hay và dễ dàng Cảm ơn :)
Talha Q

2
Lưu ý điều này đòi hỏi android.permission.GET_ACCOUNTS, được xác định là quyền 'nguy hiểm' (yêu cầu yêu cầu thời gian chạy): developer.android.com/reference/android/
mẹo

@SagiLow Bạn đã xử lý việc này như thế nào? Tôi không muốn yêu cầu người dùng, cho một quyền khác, chỉ để khiến anh ta lười biếng nhập địa chỉ email của mình :)
mã hóa vào

1
@codebasing Tôi đã không ... theo như tôi biết thì không thể.
SagiLow

2
manager.getAccountsByType ("com.google"); không hoạt động với các phiên bản Android mới hơn.
bột366

8

Có một api Android cho phép người dùng chọn địa chỉ email của họ mà không cần sự cho phép. Hãy xem tại: https://developers.google.com/identity/smartlock-passwords/android/retrieve-h gợi ý

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

Điều này sẽ hiển thị một bộ chọn trong đó người dùng có thể chọn một địa chỉ email. Kết quả sẽ được gửi trongonActivityResult()


Tôi có thể xác nhận rằng tôi đã có thể sử dụng điều này, cảm ơn vì câu trả lời hoạt động duy nhất tôi đã tìm thấy
csga5000 18/07/18

Giải pháp làm việc duy nhất, cảm ơn wirling
Zulqarnain

7

Đáng buồn thay câu trả lời không hoạt động.

Tôi đến trễ, nhưng đây là giải pháp cho ứng dụng Email Android nội bộ trừ khi nhà cung cấp thay đổi nội dung uri:

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

Sử dụng phương pháp này:

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

Lưu ý rằng điều này cần có sự GET_ACCOUNTScho phép:

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

Sau đó:

editTextEmailAddress.setText(getUserEmail());

Điều này dường như chỉ trả lại các tài khoản được liên kết với ứng dụng hiện tại - vì vậy tôi nhận được "không" trong thử nghiệm
csga5000

manager.getAccountsByType ("com.google") không hoạt động trong các phiên bản sau của Android. Và App.getInstance () từ đâu?
bột366


0

Android đã bị khóa GET_ACCOUNTSgần đây vì vậy một số câu trả lời không hoạt động với tôi. Tôi đã làm việc này trên Android 7.0 với lời cảnh báo rằng người dùng của bạn phải chịu đựng một hộp thoại cho phép.

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

Điều này không khác với các câu trả lời khác và nó giống như những câu trả lời không phù hợp với tôi - dường như bởi vì trong các phiên bản Android mới hơn, điều này chỉ trả về các tài khoản được liên kết với ứng dụng và không còn cần phải có sự cho phép.
csga5000

0

Làm việc trong hệ điều hành 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);


            }
        }
    });

<used-allow android: name = "ERIC.GET_ACCOUNTS" />
Keshav Gera

1
Nhận câu trả lời tài khoản không hiệu quả với tôi (trả về 0 tài khoản) - và tôi có thể xác nhận rằng việc gọi mã trong một cuộc gọi lại bằng nút không có sự khác biệt.
csga5000

Bộ luật này đang hoạt động nhưng gần đây tôi có vấn đề về thời gian vì vậy vui lòng kiểm tra phía chúng tôi
Keshav Gera

0

Thêm dòng đơn này trong tệp kê khai ( cho phép )

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

Sau đó dán mã này vào hoạt động của bạn

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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.