是否有唯一的Android设备ID?

是否有唯一的Android设备ID?,android,uniqueidentifier,Android,Uniqueidentifier,Android设备是否有唯一的ID?如果有,使用Java访问它的简单方法是什么?将Android ID作为64位十六进制字符串返回 import android.provider.Settings.Secure; private String android_id = Secure.getString(getContext().getContentResolver(), Secure

Android设备是否有唯一的ID?如果有,使用Java访问它的简单方法是什么?

将Android ID作为64位十六进制字符串返回

import android.provider.Settings.Secure;

private String android_id = Secure.getString(getContext().getContentResolver(),
                                                        Secure.ANDROID_ID);
    String   myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 

另请阅读唯一标识符的最佳实践:

更新:自Android的最新版本起,
Android_ID
的许多问题都已得到解决,我认为这种方法不再必要。请看一看

完全披露:我的应用程序最初使用以下方法,但不再使用此方法,现在我们使用链接到的条目中概述的方法(即,生成和保存一个)


这个问题有很多答案,其中大多数只在“某些”时间有效,不幸的是,这还不够好

根据我对设备的测试(所有手机,其中至少一部未激活):

  • 所有测试的设备都为
    TelephonyManager.getDeviceId()返回了一个值
  • 所有GSM设备(均使用SIM卡测试)都为
    TelephonyManager.getSimSerialNumber()返回了一个值
  • 对于
    getSimSerialNumber()
    ,所有CDMA设备返回空值(如预期)
  • 所有添加了谷歌账户的设备都返回了一个
    ANDROID\u ID
  • 所有CDMA设备都为
    ANDROID\u ID
    TelephonyManager.getDeviceId()
    返回相同的值(或相同值的派生值)——只要在安装过程中添加了Google帐户
  • 我还没有机会测试没有SIM卡的GSM设备,没有添加Google帐户的GSM设备,或者任何处于飞行模式的设备
  • 因此,如果您想要设备本身特有的东西,
    TM.getDeviceId()
    就足够了。显然,有些用户比其他用户更偏执,因此散列1个或多个标识符可能会很有用,这样字符串对于设备来说仍然是唯一的,但不会明确标识用户的实际设备。例如,将
    String.hashCode()
    与UUID结合使用:

    final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
    
    final String tmDevice, tmSerial, androidId;
    tmDevice = "" + tm.getDeviceId();
    tmSerial = "" + tm.getSimSerialNumber();
    androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
    
    UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
    String deviceId = deviceUuid.toString();
    
    导入库

    import android.content.Context;
    import android.telephony.TelephonyManager;
    import android.view.View;
    

    也可以考虑Wi-Fi适配器的MAC地址。检索方式如下:

    WifiManager wm = (WifiManager)Ctxt.getSystemService(Context.WIFI_SERVICE);
    return wm.getConnectionInfo().getMacAddress();
    
    需要权限
    android.permission.ACCESS\u WIFI\u STATE

    据报告,即使未连接Wi-Fi也可用。如果上面答案中的Joe在他的许多设备上尝试一下,那就太好了

    在某些设备上,当Wi-Fi关闭时,它不可用


    注意:在Android 6.x中,它返回一致的假mac地址:
    02:00:00:00:00

    以下代码使用隐藏的Android API返回设备序列号。但是,此代码在三星Galaxy标签上不起作用,因为此设备上未设置“ro.serialno”

    String serial = null;
    
    try {
        Class<?> c = Class.forName("android.os.SystemProperties");
        Method get = c.getMethod("get", String.class);
        serial = (String) get.invoke(c, "ro.serialno");
    }
    catch (Exception ignored) {
    
    }
    
    String serial=null;
    试一试{
    Class c=Class.forName(“android.os.SystemProperties”);
    方法get=c.getMethod(“get”,String.class);
    serial=(String)get.invoke(c,“ro.serialno”);
    }
    捕获(忽略异常){
    }
    
    在API级别9(Android 2.3-姜饼)中,在
    构建
    类中添加了一个字段。文档中说它代表硬件序列号。因此,如果设备上存在,它应该是唯一的


    不过,我不知道API级别>=9的所有设备是否都支持(=NOTNULL)。

    我要补充一点——我有一种独特的情况

    使用:

    deviceId = Secure.getString(this.getContext().getContentResolver(), Secure.ANDROID_ID);
    
    事实证明,尽管我的Viewsonic G平板电脑报告的DeviceID不是空的,但每个G平板电脑报告的数字都相同

    玩“Pocket Empires”很有趣,它可以让你根据“独特的”设备ID即时访问某人的帐户


    我的设备没有手机收音机。

    我想这肯定是为一个独特的ID构建一个框架的好方法。。。看看吧

    伪唯一ID,适用于所有Android设备 有些设备没有电话(如平板电脑),或者出于某种原因,您不想包括READ_phone_STATE权限。您仍然可以读取详细信息,如ROM版本、制造商名称、CPU类型和其他硬件详细信息,如果您想将ID用于串行密钥检查或其他一般用途,这些信息非常适合。以这种方式计算的ID不会是唯一的:可以找到具有相同ID的两个设备(基于相同的硬件和ROM映像),但实际应用程序中的变化可以忽略不计。为此,可以使用生成类:

    String m_szDevIDShort = "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
    
    大多数构建成员都是字符串,我们在这里做的是获取它们的长度,并通过数字模进行转换。我们有13个这样的数字,我们在前面增加了两个(35),以具有与IMEI相同的大小ID(15个数字)。这里还有其他的可能性,好吧,看看这些字符串。 返回类似于
    355715565309247
    的内容。无需特别许可,因此这种方法非常方便



    (额外信息:上面给出的技术是从上一篇文章中复制的。)

    Android开发者官方博客现在有一篇关于这个主题的完整文章,

    正如Dave Webb提到的,这篇文章涵盖了这一点。他们首选的解决方案是跟踪应用程序的安装情况,而不是跟踪设备的安装情况,这在大多数用例中都能很好地工作。这篇博文将向您展示实现该功能所需的代码,我建议您查看一下

    但是,如果您需要设备标识符而不是应用程序安装标识符,则博客文章将继续讨论解决方案。我和谷歌的某个人谈过,想在你需要做的事情中得到一些额外的澄清。以下是我在上述博客文章中未提及的关于设备标识符的发现:

    • ANDROID_ID是首选的设备标识符。ANDROID_ID在ANDROID=2.3版本上非常可靠。只有2.2有帖子中提到的问题
    • 几个装置
      import android.content.Context;
      import android.content.SharedPreferences;
      import android.provider.Settings.Secure;
      import android.telephony.TelephonyManager;
      
      import java.io.UnsupportedEncodingException;
      import java.util.UUID;
      
      public class DeviceUuidFactory {
      
          protected static final String PREFS_FILE = "device_id.xml";
          protected static final String PREFS_DEVICE_ID = "device_id";
          protected volatile static UUID uuid;
      
          public DeviceUuidFactory(Context context) {
              if (uuid == null) {
                  synchronized (DeviceUuidFactory.class) {
                      if (uuid == null) {
                          final SharedPreferences prefs = context
                                  .getSharedPreferences(PREFS_FILE, 0);
                          final String id = prefs.getString(PREFS_DEVICE_ID, null);
                          if (id != null) {
                              // Use the ids previously computed and stored in the
                              // prefs file
                              uuid = UUID.fromString(id);
                          } else {
                              final String androidId = Secure.getString(
                                  context.getContentResolver(), Secure.ANDROID_ID);
                              // Use the Android ID unless it's broken, in which case
                              // fallback on deviceId,
                              // unless it's not available, then fallback on a random
                              // number which we store to a prefs file
                              try {
                                  if (!"9774d56d682e549c".equals(androidId)) {
                                      uuid = UUID.nameUUIDFromBytes(androidId
                                              .getBytes("utf8"));
                                  } else {
                                      final String deviceId = (
                                          (TelephonyManager) context
                                          .getSystemService(Context.TELEPHONY_SERVICE))
                                          .getDeviceId();
                                      uuid = deviceId != null ? UUID
                                          .nameUUIDFromBytes(deviceId
                                                  .getBytes("utf8")) : UUID
                                          .randomUUID();
                                  }
                              } catch (UnsupportedEncodingException e) {
                                  throw new RuntimeException(e);
                              }
                              // Write the value out to the prefs file
                              prefs.edit()
                                      .putString(PREFS_DEVICE_ID, uuid.toString())
                                      .commit();
                          }
                      }
                  }
              }
          }
      
          /**
           * Returns a unique UUID for the current android device. As with all UUIDs,
           * this unique ID is "very highly likely" to be unique across all Android
           * devices. Much more so than ANDROID_ID is.
           * 
           * The UUID is generated by using ANDROID_ID as the base key if appropriate,
           * falling back on TelephonyManager.getDeviceID() if ANDROID_ID is known to
           * be incorrect, and finally falling back on a random UUID that's persisted
           * to SharedPreferences if getDeviceID() does not return a usable value.
           * 
           * In some rare circumstances, this ID may change. In particular, if the
           * device is factory reset a new device ID may be generated. In addition, if
           * a user upgrades their phone from certain buggy implementations of Android
           * 2.2 to a newer, non-buggy version of Android, the device ID may change.
           * Or, if a user uninstalls your app on a device that has neither a proper
           * Android ID nor a Device ID, this ID may change on reinstallation.
           * 
           * Note that if the code falls back on using TelephonyManager.getDeviceId(),
           * the resulting ID will NOT change after a factory reset. Something to be
           * aware of.
           * 
           * Works around a bug in Android 2.2 for many devices when using ANDROID_ID
           * directly.
           * 
           * @see http://code.google.com/p/android/issues/detail?id=10603
           * 
           * @return a UUID that may be used to uniquely identify your device for most
           *         purposes.
           */
          public UUID getDeviceUuid() {
              return uuid;
          }
      }
      
      deviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
      
      public class Installation {
          private static String sID = null;
          private static final String INSTALLATION = "INSTALLATION";
      
          public synchronized static String id(Context context) {
              if (sID == null) {
                  File installation = new File(context.getFilesDir(), INSTALLATION);
                  try {
                      if (!installation.exists())
                          writeInstallationFile(installation);
                      sID = readInstallationFile(installation);
                  } 
                  catch (Exception e) {
                      throw new RuntimeException(e);
                  }
              }
              return sID;
          }
      
          private static String readInstallationFile(File installation) throws IOException {
              RandomAccessFile f = new RandomAccessFile(installation, "r");
              byte[] bytes = new byte[(int) f.length()];
              f.readFully(bytes);
              f.close();
              return new String(bytes);
          }
      
          private static void writeInstallationFile(File installation) throws IOException {
              FileOutputStream out = new FileOutputStream(installation);
              String id = UUID.randomUUID().toString();
              out.write(id.getBytes());
              out.close();
          }
      }
      
      private static String uniqueID = null;
      private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";
      
      public synchronized static String id(Context context) {
          if (uniqueID == null) {
              SharedPreferences sharedPrefs = context.getSharedPreferences(
                      PREF_UNIQUE_ID, Context.MODE_PRIVATE);
              uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
              if (uniqueID == null) {
                  uniqueID = UUID.randomUUID().toString();
                  Editor editor = sharedPrefs.edit();
                  editor.putString(PREF_UNIQUE_ID, uniqueID);
                  editor.commit();
              }
          }
          return uniqueID;
      }
      
      <application android:label="MyApplication"
               android:backupAgent="MyBackupAgent">
          ...
          <meta-data android:name="com.google.android.backup.api_key"
              android:value="your_backup_service_key" />
      </application>
      
      public class MyBackupAgent extends BackupAgentHelper {
          // The name of the SharedPreferences file
          static final String PREFS = "user_preferences";
      
          // A key to uniquely identify the set of backup data
          static final String PREFS_BACKUP_KEY = "prefs";
      
          // Allocate a helper and add it to the backup agent
          @Override
          public void onCreate() {
              SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this,          PREFS);
              addHelper(PREFS_BACKUP_KEY, helper);
          }
      }
      
      BackupManager backupManager = new BackupManager(context);
      
        public static String getUserID(Context context) {
                  private static String uniqueID = null;
              private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";
          if (uniqueID == null) {
              SharedPreferences sharedPrefs = context.getSharedPreferences(
                      MyBackupAgent.PREFS, Context.MODE_PRIVATE);
              uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
              if (uniqueID == null) {
                  uniqueID = UUID.randomUUID().toString();
                  Editor editor = sharedPrefs.edit();
                  editor.putString(PREF_UNIQUE_ID, uniqueID);
                  editor.commit();
      
                  //backup the changes
                  BackupManager mBackupManager = new BackupManager(context);
                  mBackupManager.dataChanged();
              }
          }
      
          return uniqueID;
      }
      
      user@creep:~$ adb shell ls -l /sys/class/android_usb/android0/iSerial
      -rw-r--r-- root     root         4096 2013-01-10 21:08 iSerial
      user@creep:~$ adb shell cat /sys/class/android_usb/android0/iSerial
      0A3CXXXXXXXXXX5
      
      final TelephonyManager tm = (TelephonyManager) getBaseContext()
                  .getSystemService(SplashActivity.TELEPHONY_SERVICE);
          final String tmDevice, tmSerial, androidId;
          tmDevice = "" + tm.getDeviceId();
          Log.v("DeviceIMEI", "" + tmDevice);
          tmSerial = "" + tm.getSimSerialNumber();
          Log.v("GSM devices Serial Number[simcard] ", "" + tmSerial);
          androidId = "" + android.provider.Settings.Secure.getString(getContentResolver(),
                  android.provider.Settings.Secure.ANDROID_ID);
          Log.v("androidId CDMA devices", "" + androidId);
          UUID deviceUuid = new UUID(androidId.hashCode(),
                  ((long) tmDevice.hashCode() << 32) | tmSerial.hashCode());
          String deviceId = deviceUuid.toString();
          Log.v("deviceIdUUID universally unique identifier", "" + deviceId);
          String deviceModelName = android.os.Build.MODEL;
          Log.v("Model Name", "" + deviceModelName);
          String deviceUSER = android.os.Build.USER;
          Log.v("Name USER", "" + deviceUSER);
          String devicePRODUCT = android.os.Build.PRODUCT;
          Log.v("PRODUCT", "" + devicePRODUCT);
          String deviceHARDWARE = android.os.Build.HARDWARE;
          Log.v("HARDWARE", "" + deviceHARDWARE);
          String deviceBRAND = android.os.Build.BRAND;
          Log.v("BRAND", "" + deviceBRAND);
          String myVersion = android.os.Build.VERSION.RELEASE;
          Log.v("VERSION.RELEASE", "" + myVersion);
          int sdkVersion = android.os.Build.VERSION.SDK_INT;
          Log.v("VERSION.SDK_INT", "" + sdkVersion);
      
      <uses-permission android:name="android.permission.READ_PHONE_STATE" />
      
      String identifier = null;
      TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE));
      if (tm != null)
            identifier = tm.getDeviceId();
      if (identifier == null || identifier .length() == 0)
            identifier = Secure.getString(activity.getContentResolver(),Secure.ANDROID_ID);
      
      public static String getDeviceId(Context ctx)
      {
          TelephonyManager tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
      
          String tmDevice = tm.getDeviceId();
          String androidId = Secure.getString(ctx.getContentResolver(), Secure.ANDROID_ID);
          String serial = null;
          if(Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) serial = Build.SERIAL;
      
          if(tmDevice != null) return "01" + tmDevice;
          if(androidId != null) return "02" + androidId;
          if(serial != null) return "03" + serial;
          // other alternatives (i.e. Wi-Fi MAC, Bluetooth MAC, etc.)
      
          return null;
      }
      
      if API >= 9/10: (99.5% of devices)
      
      return unique ID containing serial id (rooted devices may be different)
      
      else
      
      return the unique ID of build information (may overlap data - API < 9)
      
      /**
       * Return pseudo unique ID
       * @return ID
       */
      public static String getUniquePsuedoID() {
          // If all else fails, if the user does have lower than API 9 (lower
          // than Gingerbread), has reset their device or 'Secure.ANDROID_ID'
          // returns 'null', then simply the ID returned will be solely based
          // off their Android device information. This is where the collisions
          // can happen.
          // Thanks http://www.pocketmagic.net/?p=1662!
          // Try not to use DISPLAY, HOST or ID - these items could change.
          // If there are collisions, there will be overlapping data
          String m_szDevIDShort = "35" + (Build.BOARD.length() % 10) + (Build.BRAND.length() % 10) + (Build.CPU_ABI.length() % 10) + (Build.DEVICE.length() % 10) + (Build.MANUFACTURER.length() % 10) + (Build.MODEL.length() % 10) + (Build.PRODUCT.length() % 10);
      
          // Thanks to @Roman SL!
          // https://stackoverflow.com/a/4789483/950427
          // Only devices with API >= 9 have android.os.Build.SERIAL
          // http://developer.android.com/reference/android/os/Build.html#SERIAL
          // If a user upgrades software or roots their device, there will be a duplicate entry
          String serial = null;
          try {
              serial = android.os.Build.class.getField("SERIAL").get(null).toString();
      
              // Go ahead and return the serial for api => 9
              return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
          } catch (Exception exception) {
              // String needs to be initialized
              serial = "serial"; // some value
          }
      
          // Thanks @Joe!
          // https://stackoverflow.com/a/2853253/950427
          // Finally, combine the values we have found by using the UUID class to create a unique identifier
          return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
      }
      
      <uses-permission android:name="android.permission.INTERNET" />
      
      import com.google.android.gms.ads.identifier.AdvertisingIdClient;
      import com.google.android.gms.ads.identifier.AdvertisingIdClient.Info;
      import com.google.android.gms.common.GooglePlayServicesAvailabilityException;
      import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
      import java.io.IOException;
      ...
      
      // Do not call this function from the main thread. Otherwise, 
      // an IllegalStateException will be thrown.
      public void getIdThread() {
      
        Info adInfo = null;
        try {
          adInfo = AdvertisingIdClient.getAdvertisingIdInfo(mContext);
      
        } catch (IOException exception) {
          // Unrecoverable error connecting to Google Play services (e.g.,
          // the old version of the service doesn't support getting AdvertisingId).
       
        } catch (GooglePlayServicesAvailabilityException exception) {
          // Encountered a recoverable error connecting to Google Play services. 
      
        } catch (GooglePlayServicesNotAvailableException exception) {
          // Google Play services is not available entirely.
        }
        final String id = adInfo.getId();
        final boolean isLAT = adInfo.isLimitAdTrackingEnabled();
      }
      
      import android.Manifest.permission;
      import android.bluetooth.BluetoothAdapter;
      import android.content.Context;
      import android.content.pm.PackageManager;
      import android.net.wifi.WifiManager;
      import android.provider.Settings.Secure;
      import android.telephony.TelephonyManager;
      import android.util.Log;
      
      // TODO : hash
      public final class DeviceIdentifier {
      
          private DeviceIdentifier() {}
      
          /** @see http://code.google.com/p/android/issues/detail?id=10603 */
          private static final String ANDROID_ID_BUG_MSG = "The device suffers from "
              + "the Android ID bug - its ID is the emulator ID : "
              + IDs.BUGGY_ANDROID_ID;
          private static volatile String uuid; // volatile needed - see EJ item 71
          // need lazy initialization to get a context
      
          /**
           * Returns a unique identifier for this device. The first (in the order the
           * enums constants as defined in the IDs enum) non null identifier is
           * returned or a DeviceIDException is thrown. A DeviceIDException is also
           * thrown if ignoreBuggyAndroidID is false and the device has the Android ID
           * bug
           *
           * @param ctx
           *            an Android constant (to retrieve system services)
           * @param ignoreBuggyAndroidID
           *            if false, on a device with the android ID bug, the buggy
           *            android ID is not returned instead a DeviceIDException is
           *            thrown
           * @return a *device* ID - null is never returned, instead a
           *         DeviceIDException is thrown
           * @throws DeviceIDException
           *             if none of the enum methods manages to return a device ID
           */
          public static String getDeviceIdentifier(Context ctx,
                  boolean ignoreBuggyAndroidID) throws DeviceIDException {
              String result = uuid;
              if (result == null) {
                  synchronized (DeviceIdentifier.class) {
                      result = uuid;
                      if (result == null) {
                          for (IDs id : IDs.values()) {
                              try {
                                  result = uuid = id.getId(ctx);
                              } catch (DeviceIDNotUniqueException e) {
                                  if (!ignoreBuggyAndroidID)
                                      throw new DeviceIDException(e);
                              }
                              if (result != null) return result;
                          }
                          throw new DeviceIDException();
                      }
                  }
              }
              return result;
          }
      
          private static enum IDs {
              TELEPHONY_ID {
      
                  @Override
                  String getId(Context ctx) {
                      // TODO : add a SIM based mechanism ? tm.getSimSerialNumber();
                      final TelephonyManager tm = (TelephonyManager) ctx
                              .getSystemService(Context.TELEPHONY_SERVICE);
                      if (tm == null) {
                          w("Telephony Manager not available");
                          return null;
                      }
                      assertPermission(ctx, permission.READ_PHONE_STATE);
                      return tm.getDeviceId();
                  }
              },
              ANDROID_ID {
      
                  @Override
                  String getId(Context ctx) throws DeviceIDException {
                      // no permission needed !
                      final String andoidId = Secure.getString(
                          ctx.getContentResolver(),
                          android.provider.Settings.Secure.ANDROID_ID);
                      if (BUGGY_ANDROID_ID.equals(andoidId)) {
                          e(ANDROID_ID_BUG_MSG);
                          throw new DeviceIDNotUniqueException();
                      }
                      return andoidId;
                  }
              },
              WIFI_MAC {
      
                  @Override
                  String getId(Context ctx) {
                      WifiManager wm = (WifiManager) ctx
                              .getSystemService(Context.WIFI_SERVICE);
                      if (wm == null) {
                          w("Wifi Manager not available");
                          return null;
                      }
                      assertPermission(ctx, permission.ACCESS_WIFI_STATE); // I guess
                      // getMacAddress() has no java doc !!!
                      return wm.getConnectionInfo().getMacAddress();
                  }
              },
              BLUETOOTH_MAC {
      
                  @Override
                  String getId(Context ctx) {
                      BluetoothAdapter ba = BluetoothAdapter.getDefaultAdapter();
                      if (ba == null) {
                          w("Bluetooth Adapter not available");
                          return null;
                      }
                      assertPermission(ctx, permission.BLUETOOTH);
                      return ba.getAddress();
                  }
              }
              // TODO PSEUDO_ID
              // http://www.pocketmagic.net/2011/02/android-unique-device-id/
              ;
      
              static final String BUGGY_ANDROID_ID = "9774d56d682e549c";
              private final static String TAG = IDs.class.getSimpleName();
      
              abstract String getId(Context ctx) throws DeviceIDException;
      
              private static void w(String msg) {
                  Log.w(TAG, msg);
              }
      
              private static void e(String msg) {
                  Log.e(TAG, msg);
              }
          }
      
          private static void assertPermission(Context ctx, String perm) {
              final int checkPermission = ctx.getPackageManager().checkPermission(
                  perm, ctx.getPackageName());
              if (checkPermission != PackageManager.PERMISSION_GRANTED) {
                  throw new SecurityException("Permission " + perm + " is required");
              }
          }
      
          // =========================================================================
          // Exceptions
          // =========================================================================
          public static class DeviceIDException extends Exception {
      
              private static final long serialVersionUID = -8083699995384519417L;
              private static final String NO_ANDROID_ID = "Could not retrieve a "
                  + "device ID";
      
              public DeviceIDException(Throwable throwable) {
                  super(NO_ANDROID_ID, throwable);
              }
      
              public DeviceIDException(String detailMessage) {
                  super(detailMessage);
              }
      
              public DeviceIDException() {
                  super(NO_ANDROID_ID);
              }
          }
      
          public static final class DeviceIDNotUniqueException extends
                  DeviceIDException {
      
              private static final long serialVersionUID = -8940090896069484955L;
      
              public DeviceIDNotUniqueException() {
                  super(ANDROID_ID_BUG_MSG);
              }
          }
      }
      
      String deviceId;
      final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
      if (mTelephony.getDeviceId() != null) {
          deviceId = mTelephony.getDeviceId();
      }
      else {
          deviceId = Secure.getString(
                         getApplicationContext().getContentResolver(),
                         Secure.ANDROID_ID);
      }
      
      final TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);            
      String myAndroidDeviceId = mTelephony.getDeviceId(); 
      
          String   myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
      
      public String getUniqueID(){    
          String myAndroidDeviceId = "";
          TelephonyManager mTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
          if (mTelephony.getDeviceId() != null){
              myAndroidDeviceId = mTelephony.getDeviceId(); 
          }else{
               myAndroidDeviceId = Secure.getString(getApplicationContext().getContentResolver(), Secure.ANDROID_ID); 
          }
          return myAndroidDeviceId;
      }
      
      InstanceID iid = InstanceID.getInstance( context );   // Google docs are wrong - this requires context
      String id = iid.getId();  // blocking call
      
      List<NetworkInterface> interfacesList = Collections.list(NetworkInterface.getNetworkInterfaces());
      
      for (NetworkInterface interface : interfacesList) {
         // This will give you the interface MAC ADDRESS
         interface.getHardwareAddress();
      }
      
      @SuppressWarnings("deprecation")
      @SuppressLint("HardwareIds")
      public static String generateDeviceIdentifier(Context context) {
      
              String pseudoId = "35" +
                      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;
      
              String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
      
              BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
              String btId = "";
      
              if (bluetoothAdapter != null) {
                  btId = bluetoothAdapter.getAddress();
              }
      
              String longId = pseudoId + androidId + btId;
      
              try {
                  MessageDigest messageDigest = MessageDigest.getInstance("MD5");
                  messageDigest.update(longId.getBytes(), 0, longId.length());
      
                  // get md5 bytes
                  byte md5Bytes[] = messageDigest.digest();
      
                  // creating a hex string
                  String identifier = "";
      
                  for (byte md5Byte : md5Bytes) {
                      int b = (0xFF & md5Byte);
      
                      // if it is a single digit, make sure it have 0 in front (proper padding)
                      if (b <= 0xF) {
                          identifier += "0";
                      }
      
                      // add number to string
                      identifier += Integer.toHexString(b);
                  }
      
                  // hex string to uppercase
                  identifier = identifier.toUpperCase();
                  return identifier;
              } catch (Exception e) {
                  Log.e("TAG", e.toString());
              }
              return "";
      }
      
      import android.telephony.TelephonyManager;
      import android.content.Context;
      // ...
      TelephonyManager telephonyManager;
      telephonyManager = (TelephonyManager) getSystemService(Context.
                      TELEPHONY_SERVICE);
      /*
      * getDeviceId() returns the unique device ID.
      * For example,the IMEI for GSM and the MEID or ESN for CDMA phones.
      */
      String deviceId = telephonyManager.getDeviceId();
      /*
      * getSubscriberId() returns the unique subscriber ID,
      */
      String subscriberId = telephonyManager.getSubscriberId();
      
      implementation 'com.google.firebase:firebase-messaging:20.2.4'
      
      String reliableIdentifier = FirebaseInstanceId.getInstance().getId();