Android 获取唯一标识

mac2023-02-01  9

一、前言

app开发过程中,需要对本地数据进行加密,因此了解了app所能获取到的一些标示。

常见唯一标示 imei

Android_id

mac地址

Installtion ID : UUID

Pseudo-Unique ID

二、IMEI 需要获取权限 <uses-permission android:name="android.permission.READ_PHONE_STATE"/> 获取方法

TelephonyManager telephonyManager =(TelephonyManager)context.getSystemService(context.TELEPHONY_SERVICE); String imei = telephonyManager.getDeviceId(); 问题: Android6.0后当无法获取到该权限后,方法直接报错,imei作为唯一标示可靠性太差。

Android_id 获取 String ANDROID_ID = Settings.System.getString(getContentResolver(), Settings.System.ANDROID_ID); 问题: Android_id是不需要权限,但它跟手机rom和手机厂商有关(Android_id是设备首次运行随机生成的64位数字)有点手机是获取不到,恢复出厂设置时也会改变,可靠性也较差

Mac地址 获取方法

/**      * Android 6.0 之前(不包括6.0)获取mac地址      * 必须的权限 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>      * @param context * @return      */     public static String getMacDefault(Context context) {         String mac = "";         if (context == null) {             return mac;         }         WifiManager wifi = (WifiManager)context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);         WifiInfo info = null;         try {             info = wifi.getConnectionInfo();         } catch (Exception e) {             e.printStackTrace();         }           if (info == null) {             return null;         }         mac = info.getMacAddress();         if (!TextUtils.isEmpty(mac)) {             mac = mac.toUpperCase(Locale.ENGLISH);         }         return mac;     }       /**      * Android 6.0-Android 7.0 获取mac地址      */     public static String getMacAddress() {         String macSerial = null;         String str = "";           try {             Process pp = Runtime.getRuntime().exec("cat/sys/class/net/wlan0/address");             InputStreamReader ir = new InputStreamReader(pp.getInputStream());             LineNumberReader input = new LineNumberReader(ir);               while (null != str) {                 str = input.readLine();                 if (str != null) {                     macSerial = str.trim();//去空格                     break;                 }             }         } catch (IOException ex) {             // 赋予默认值             ex.printStackTrace();         }           return macSerial;     }         /**      * 通过网络接口取      * @return      */     private static String getNewMac() {         try {             List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());             for (NetworkInterface nif : all) {                 if (!nif.getName().equalsIgnoreCase("wlan0")) continue;                   byte[] macBytes = nif.getHardwareAddress();                 if (macBytes == null) {                     return null;                 }                   StringBuilder res1 = new StringBuilder();                 for (byte b : macBytes) {                     res1.append(String.format("%02X:", b));                 }                   if (res1.length() > 0) {                     res1.deleteCharAt(res1.length() - 1);                 }                 return res1.toString();             }         } catch (Exception ex) {             ex.printStackTrace();         }         return null;     }     /**      * 获取mac地址(适配所有Android版本)      * @return      */     public static String  getMac( Context context) {         String mac = "";         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {             mac = getMacDefault(context);         } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {             mac = getMacAddress();         } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {             mac = getNewMac();         }         return mac;     } 问题: 手机必须具有上网功能,使用场景有局限性

Installtion ID : UUID 这种方式的原理是在程序安装后第一次运行时生成一个ID,该方式和设备唯一标识不一样,不同的应用程序会产生不同的ID,同一个程序重新安装也会不同。所以这不是设备的唯一ID,但是可以保证每个用户的ID是不同的。可以说是用来标识每一份应用程序的唯一ID(即Installtion 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();     } } 问题: 无法唯一的标示,多次安装多次不同

Pseudo-Unique ID     /**      * Return pseudo unique ID      *      * @return ID      */     public static String getUniquePsuedoDeviceID() {         // 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); //        Log.i("", "getUniquePsuedoDeviceID: "+m_szDevIDShort);         // Only devices with API >= 9 have android.os.Build.SERIAL         String serial = null;         try {             serial = 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!         // http://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();     } 问题: 模拟器和刷机带来的一样的id,但能保证99.5%的成功率

总结 到现在发现没有一个是完全靠谱的方式,那就呵呵。 那就其他人是咋解决的呢?发现无外乎这些方法,那大厂是如何解决的呢?

解决 utdid4all-1.1.5.3_proguard.jar 借助上面阿里的jar

UTDevice.getUtdid(AppApplication.in()) 获取一个稳定的id

最新回复(0)