Как получить IMEI/ESN устройства программно в Android?

Для уникальной идентификации каждого устройства я хотел бы использовать IMEI (или номер ESN для устройств CDMA). Как получить доступ к этому программно?

22 ответа

Решение

Вы хотите позвонить android.telephony.TelephonyManager.getDeviceId(),

Это вернет любую строку, однозначно идентифицирующую устройство (IMEI в GSM, MEID для CDMA).

Вам понадобится следующее разрешение в вашемAndroidManifest.xml:

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

для того, чтобы сделать это.

При этом будьте осторожны с этим. Пользователи не только будут удивляться, почему ваше приложение получает доступ к своему стеку телефонии, но и будет сложно перенести данные, если пользователь получит новое устройство.

Обновление: как упоминалось в комментариях ниже, это не безопасный способ аутентификации пользователей, и он вызывает проблемы конфиденциальности. Не рекомендуется Вместо этого посмотрите API входа в Google+, если хотите внедрить систему входа без трения.

API резервного копирования Android также доступен, если вы просто хотите облегчить способ сохранения набора строк, когда пользователь перезагружает свой телефон (или покупает новое устройство).

В дополнение к ответу Тревора Джонса вы можете использовать это следующим образом:

TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.getDeviceId();

И вы должны добавить следующее разрешение в ваш файл Manifest.xml:

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

В эмуляторе вы, вероятно, получите значение "00000...". getDeviceId() возвращает NULL, если идентификатор устройства недоступен.

Я использую следующий код для получения IMEI или использую Secure.ANDROID_ID в качестве альтернативы, когда устройство не имеет возможностей телефона:

/**
 * Returns the unique identifier for the device
 *
 * @return unique identifier for the device
 */
public String getDeviceIMEI() {
    String deviceUniqueIdentifier = null;
    TelephonyManager tm = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
    if (null != tm) {
        deviceUniqueIdentifier = tm.getDeviceId();
    }
    if (null == deviceUniqueIdentifier || 0 == deviceUniqueIdentifier.length()) {
        deviceUniqueIdentifier = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID);
    }
    return deviceUniqueIdentifier;
}

Или вы можете использовать настройку ANDROID_ID из Android.Provider.Settings.System (как описано здесь strazerre.com).

Это имеет то преимущество, что не требует специальных разрешений, но может измениться, если другое приложение имеет доступ для записи и изменяет его (что, по-видимому, необычно, но не невозможно).

Просто для справки вот код из блога:

import android.provider.Settings;
import android.provider.Settings.System;   

String androidID = System.getString(this.getContentResolver(),Secure.ANDROID_ID);

Замечание по реализации: если идентификатор имеет решающее значение для архитектуры системы, вы должны знать, что на практике некоторые из телефонов и планшетов с очень низким уровнем Android были обнаружены с повторным использованием идентификатора ANDROID_ID (значение 9774d56d682e549c было показано в наших журналах)

От: http://mytechead.wordpress.com/2011/08/28/how-to-get-imei-number-of-android-device/:

Следующий код помогает в получении IMEI количества устройств Android:

TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String device_id = tm.getDeviceId();

Разрешения, необходимые в манифесте Android:

android.permission.READ_PHONE_STATE

ПРИМЕЧАНИЕ. В случае планшетов или устройств, которые не могут выполнять функции мобильного телефона, IMEI будет нулевым.

Получить IMEI (международный идентификатор мобильного оборудования)

public String getIMEI(Activity activity) {
    TelephonyManager telephonyManager = (TelephonyManager) activity
            .getSystemService(Context.TELEPHONY_SERVICE);
    return telephonyManager.getDeviceId();
}

получить уникальный идентификатор устройства

public String getDeviceUniqueID(Activity activity){
    String device_unique_id = Secure.getString(activity.getContentResolver(),
            Secure.ANDROID_ID);
    return device_unique_id;
}

Для Android 6.0+ игра изменилась, поэтому я предлагаю вам использовать это;

Лучший способ - во время выполнения, иначе вы получите ошибки разрешения.

   /**
 * A loading screen after AppIntroActivity.
 */
public class LoadingActivity extends BaseActivity {
private static final int MY_PERMISSIONS_REQUEST_READ_PHONE_STATE = 0;
private TextView loading_tv2;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_loading);

    //trigger 'loadIMEI'
    loadIMEI();
    /** Fading Transition Effect */
    overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
}

/**
 * Called when the 'loadIMEI' function is triggered.
 */
public void loadIMEI() {
    // Check if the READ_PHONE_STATE permission is already available.
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
            != PackageManager.PERMISSION_GRANTED) {
        // READ_PHONE_STATE permission has not been granted.
        requestReadPhoneStatePermission();
    } else {
        // READ_PHONE_STATE permission is already been granted.
        doPermissionGrantedStuffs();
    }
}



/**
 * Requests the READ_PHONE_STATE permission.
 * If the permission has been denied previously, a dialog will prompt the user to grant the
 * permission, otherwise it is requested directly.
 */
private void requestReadPhoneStatePermission() {
    if (ActivityCompat.shouldShowRequestPermissionRationale(this,
            Manifest.permission.READ_PHONE_STATE)) {
        // Provide an additional rationale to the user if the permission was not granted
        // and the user would benefit from additional context for the use of the permission.
        // For example if the user has previously denied the permission.
        new AlertDialog.Builder(LoadingActivity.this)
                .setTitle("Permission Request")
                .setMessage(getString(R.string.permission_read_phone_state_rationale))
                .setCancelable(false)
                .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        //re-request
                        ActivityCompat.requestPermissions(LoadingActivity.this,
                                new String[]{Manifest.permission.READ_PHONE_STATE},
                                MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
                    }
                })
                .setIcon(R.drawable.onlinlinew_warning_sign)
                .show();
    } else {
        // READ_PHONE_STATE permission has not been granted yet. Request it directly.
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE},
                MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);
    }
}

/**
 * Callback received when a permissions request has been completed.
 */
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {

    if (requestCode == MY_PERMISSIONS_REQUEST_READ_PHONE_STATE) {
        // Received permission result for READ_PHONE_STATE permission.est.");
        // Check if the only required permission has been granted
        if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // READ_PHONE_STATE permission has been granted, proceed with displaying IMEI Number
            //alertAlert(getString(R.string.permision_available_read_phone_state));
            doPermissionGrantedStuffs();
        } else {
            alertAlert(getString(R.string.permissions_not_granted_read_phone_state));
          }
    }
}

private void alertAlert(String msg) {
    new AlertDialog.Builder(LoadingActivity.this)
            .setTitle("Permission Request")
            .setMessage(msg)
            .setCancelable(false)
            .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    // do somthing here
                }
            })
            .setIcon(R.drawable.onlinlinew_warning_sign)
            .show();
}


public void doPermissionGrantedStuffs() {
    //Have an  object of TelephonyManager
    TelephonyManager tm =(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
    //Get IMEI Number of Phone  //////////////// for this example i only need the IMEI
    String IMEINumber=tm.getDeviceId();

    /************************************************
     * **********************************************
     * This is just an icing on the cake
     * the following are other children of TELEPHONY_SERVICE
     *
     //Get Subscriber ID
     String subscriberID=tm.getDeviceId();

     //Get SIM Serial Number
     String SIMSerialNumber=tm.getSimSerialNumber();

     //Get Network Country ISO Code
     String networkCountryISO=tm.getNetworkCountryIso();

     //Get SIM Country ISO Code
     String SIMCountryISO=tm.getSimCountryIso();

     //Get the device software version
     String softwareVersion=tm.getDeviceSoftwareVersion()

     //Get the Voice mail number
     String voiceMailNumber=tm.getVoiceMailNumber();


     //Get the Phone Type CDMA/GSM/NONE
     int phoneType=tm.getPhoneType();

     switch (phoneType)
     {
     case (TelephonyManager.PHONE_TYPE_CDMA):
     // your code
     break;
     case (TelephonyManager.PHONE_TYPE_GSM)
     // your code
     break;
     case (TelephonyManager.PHONE_TYPE_NONE):
     // your code
     break;
     }

     //Find whether the Phone is in Roaming, returns true if in roaming
     boolean isRoaming=tm.isNetworkRoaming();
     if(isRoaming)
     phoneDetails+="\nIs In Roaming : "+"YES";
     else
     phoneDetails+="\nIs In Roaming : "+"NO";


     //Get the SIM state
     int SIMState=tm.getSimState();
     switch(SIMState)
     {
     case TelephonyManager.SIM_STATE_ABSENT :
     // your code
     break;
     case TelephonyManager.SIM_STATE_NETWORK_LOCKED :
     // your code
     break;
     case TelephonyManager.SIM_STATE_PIN_REQUIRED :
     // your code
     break;
     case TelephonyManager.SIM_STATE_PUK_REQUIRED :
     // your code
     break;
     case TelephonyManager.SIM_STATE_READY :
     // your code
     break;
     case TelephonyManager.SIM_STATE_UNKNOWN :
     // your code
     break;

     }
     */
    // Now read the desired content to a textview.
    loading_tv2 = (TextView) findViewById(R.id.loading_tv2);
    loading_tv2.setText(IMEINumber);
}
}

Надеюсь, это поможет вам или кому-то.

Как и в API 26, getDeviceId() устарела, поэтому вы можете использовать следующий код для обслуживания API 26 и более ранних версий.

TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
String imei="";
if (android.os.Build.VERSION.SDK_INT >= 26) {
  imei=telephonyManager.getImei();
}
else
{
  imei=telephonyManager.getDeviceId();
}

Не забудьте добавить запрос на разрешение для "READ_PHONE_STATE" для использования вышеуказанного кода.

Новое обновление:

Для Android версии 6 и выше MAC-адрес WLAN устарел, следуйте ответу Тревора Джонса

Обновить:

Для однозначной идентификации устройств вы можете использовать Secure.ANDROID_ID.

Старый ответ:

Недостатки использования IMEI в качестве уникального идентификатора устройства:

  • IMEI зависит от слота Simcard устройства, поэтому получить IMEI для устройств, которые не используют Simcard, невозможно. В устройствах Dual sim мы получаем 2 разных IMEI для одного и того же устройства, поскольку у него есть 2 слота для симкарты.

Вы можете использовать строку MAC-адреса WLAN (не рекомендуется для Marshmallow и Marshmallow+, так как MAC-адрес WLAN устарел при переходе в Marshmallow. Таким образом, вы получите поддельное значение)

Мы также можем получить уникальный идентификатор для телефонов Android, используя MAC-адрес WLAN. MAC-адрес уникален для всех устройств и работает для всех типов устройств.

Преимущества использования WLAN MAC-адреса в качестве идентификатора устройства:

  • Это уникальный идентификатор для всех типов устройств (смартфонов и планшетов).

  • Он остается уникальным, если приложение переустанавливается

Недостатки использования MAC-адреса WLAN в качестве идентификатора устройства:

  • Дай вам фиктивную ценность от Зефира и выше.

  • Если устройство не имеет оборудования Wi-Fi, тогда вы получаете нулевой MAC-адрес, но, как правило, видно, что большинство устройств Android имеют оборудование Wi-Fi, и на рынке практически нет устройств без оборудования Wi-Fi.

ИСТОЧНИК: technetexperts.com

Метод getDeviceId() TelephonyManager возвращает уникальный идентификатор устройства, например, IMEI для GSM и MEID или ESN для телефонов CDMA. Вернуть ноль, если идентификатор устройства недоступен.

Java-код

package com.AndroidTelephonyManager;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.widget.TextView;

public class AndroidTelephonyManager extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    TextView textDeviceID = (TextView)findViewById(R.id.deviceid);

    //retrieve a reference to an instance of TelephonyManager
    TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);

    textDeviceID.setText(getDeviceID(telephonyManager));

}

String getDeviceID(TelephonyManager phonyManager){

 String id = phonyManager.getDeviceId();
 if (id == null){
  id = "not available";
 }

 int phoneType = phonyManager.getPhoneType();
 switch(phoneType){
 case TelephonyManager.PHONE_TYPE_NONE:
  return "NONE: " + id;

 case TelephonyManager.PHONE_TYPE_GSM:
  return "GSM: IMEI=" + id;

 case TelephonyManager.PHONE_TYPE_CDMA:
  return "CDMA: MEID/ESN=" + id;

 /*
  *  for API Level 11 or above
  *  case TelephonyManager.PHONE_TYPE_SIP:
  *   return "SIP";
  */

 default:
  return "UNKNOWN: ID=" + id;
 }

}
}

XML

<linearlayout android:layout_height="fill_parent" android:layout_width="fill_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android">
<textview android:layout_height="wrap_content" android:layout_width="fill_parent" android:text="@string/hello">
<textview android:id="@+id/deviceid" android:layout_height="wrap_content" android:layout_width="fill_parent">
</textview></textview></linearlayout> 

Требуется разрешение READ_PHONE_STATE в файле манифеста.

Вы можете использовать эту функцию TelephonyManager TELEPHONY_SERVICE, чтобы получить уникальный идентификатор устройства. Требуется разрешение: READ_PHONE_STATE.

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

Например, IMEI для GSM и MEID или ESN для телефонов CDMA.

/**
 * Gets the device unique id called IMEI. Sometimes, this returns 00000000000000000 for the
 * rooted devices.
 **/
public static String getDeviceImei(Context ctx) {
    TelephonyManager telephonyManager = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
    return telephonyManager.getDeviceId();
}

Вернуть ноль, если идентификатор устройства недоступен.

Попробуйте это (необходимо получить первый IMEI всегда)

TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        if (ActivityCompat.checkSelfPermission(LoginActivity.this,Manifest.permission.READ_PHONE_STATE)!= PackageManager.PERMISSION_GRANTED) {

         return;
}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                if (mTelephony.getPhoneCount() == 2) {
                    IME = mTelephony.getImei(0);
                }else{
                    IME = mTelephony.getImei();
                }
            }else{
                if (mTelephony.getPhoneCount() == 2) {
                    IME = mTelephony.getDeviceId(0);
                } else {
                    IME = mTelephony.getDeviceId();
                }
            }
        } else {
            IME = mTelephony.getDeviceId();
        }

Метод getDeviceId() устарела. There a new method for this getImei(int)

Проверьте здесь

Используйте код ниже, чтобы получить номер IMEI:

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
System.out.println("IMEI::" + telephonyManager.getDeviceId());

Для Android 10 У меня работает следующий код.

val uid: String = Settings.Secure.getString(ctx.applicationContext.contentResolver, Settings.Secure.ANDROID_ID)
if (ContextCompat.checkSelfPermission(ctx, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
            imei = when {
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q -> {
                    uid
                }
                Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
                    telephonyManager.imei
                }
                else -> {
                    telephonyManager.deviceId
                }
            }
        }

Вам понадобится следующее разрешение в вашем AndroidManifest.xml:

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

Чтобы получить IMEI (международный идентификатор мобильного оборудования) и если он выше уровня API 26, то получимtelephonyManager.getImei()как null, поэтому для этого мы используем ANDROID_ID в качестве уникального идентификатора.

 public static String getIMEINumber(@NonNull final Context context)
            throws SecurityException, NullPointerException {
        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        String imei;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            assert tm != null;
            imei = tm.getImei();
            //this change is for Android 10 as per security concern it will not provide the imei number.
            if (imei == null) {
                imei = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
            }
        } else {
            assert tm != null;
            if (tm.getDeviceId() != null && !tm.getDeviceId().equals("000000000000000")) {
                imei = tm.getDeviceId();
            } else {
                imei = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
            }
        }

        return imei;
    }

Ограничение на не сбрасываемые идентификаторы устройств

Начиная с Android 10 приложения должны иметь READ_PRIVILEGED_PHONE_STATE привилегированное разрешение для доступа к не сбрасываемым идентификаторам устройства, которые включают как IMEI, так и серийный номер.

Для API уровня 11 или выше:

case TelephonyManager.PHONE_TYPE_SIP: 
return "SIP";

TelephonyManager tm= (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
textDeviceID.setText(getDeviceID(tm));

Код Kotlin для получения DeviceId ( IMEI) с разрешением обработки и проверкой сопоставимости для всех версий Android:

 val  telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
        == PackageManager.PERMISSION_GRANTED) {
        // Permission is  granted
        val imei : String? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)  telephonyManager.imei
        // older OS  versions
        else  telephonyManager.deviceId

        imei?.let {
            Log.i("Log", "DeviceId=$it" )
        }

    } else {  // Permission is not granted

    }

Также добавьте это разрешение в AndroidManifest.xml:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/> <!-- IMEI-->

Используйте код ниже:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        String[] permissions = {Manifest.permission.READ_PHONE_STATE};
        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(permissions, READ_PHONE_STATE);
        }
    } else {
        try {
            TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            String imei = telephonyManager.getDeviceId();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

И вызовите метод onRequestPermissionsResult, следующий за кодом:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode) {
        case READ_PHONE_STATE:
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED)
                try {
                    TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
                    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
                        return;
                    }
                    String imei = telephonyManager.getDeviceId();

                } catch (Exception e) {
                    e.printStackTrace();
                }
    }
}

Добавьте следующее разрешение в свой AndroidManifest.xml:

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

Невозможно получить номер imei с мобильных телефонов andorid 10+ или 29+, вот альтернативная функция, которая будет использоваться для создания номера imei для устройств.

      public  static String getDeviceID(){
    String devIDShort = "35" + //we make this look like a valid IMEI
            Build.BOARD.length()%10+ Build.BRAND.length()%10 +
            Build.CPU_ABI.length()%10 + Build.DEVICE.length()%10 +
            Build.DISPLAY.length()%10 + Build.HOST.length()%10 +
            Build.ID.length()%10 + Build.MANUFACTURER.length()%10 +
            Build.MODEL.length()%10 + Build.PRODUCT.length()%10 +
            Build.TAGS.length()%10 + Build.TYPE.length()%10 +
            Build.USER.length()%10 ; //13 digits

    return  devIDShort;
}

Для тех, кто ищет версию Kotlin, вы можете использовать что-то вроде этого;

private fun telephonyService() {
    val telephonyManager = getSystemService(TELEPHONY_SERVICE) as TelephonyManager
    val imei = if (android.os.Build.VERSION.SDK_INT >= 26) {
        Timber.i("Phone >= 26 IMEI")
        telephonyManager.imei
    } else {
        Timber.i("Phone IMEI < 26")
        telephonyManager.deviceId
    }

    Timber.i("Phone IMEI $imei")
}

ПРИМЕЧАНИЕ: вы должны обернуть telephonyService() выше с проверкой разрешения, используя checkSelfPermission или любым другим способом, который вы используете.

Также добавьте это разрешение в файл манифеста;

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
Другие вопросы по тегам