概述
有时需要对用户设备进行标识,所以希望能够得到一个稳定可靠并且唯一的识别码。虽然Android系统中提供了这样设备识别码,但是由于Android系统版本、厂商定制系统中的Bug等限制,稳定性和唯一性并不理想。
唯一标识码这东西在网络应用中非常有用,例如检测是否重复注册之类的。下面就来介绍几种标识码:
1.DEVICE_ID;
2.MAC ADDRESS;
3.Sim Serial Number;
4.Serial Number;
5.ANDROID_ID;
6.Installtion ID : UUID;
7.DEVICE_ID:UUID;
DEVICE_ID
概念: 是区别移动设备的标志,储存在移动设备中,可用于监控被窃或无效的移动设备。
关键代码:
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String IMEI = tm.getDeviceId();
优点:
1.根据不同的手机设备返回IMEI,MEID或者ESN码,唯一性良好 。
不足:
1.非手机:如平板电脑,像这样设备没有通话的硬件功能,系统中也就没有TELEPHONY_SERVICE,自然也就无法获得DEVICE_ID;
2.权限问题:获取DEVICE_ID需要READ_PHONE_STATE权限;
3.厂商定制系统中的Bug:少数手机设备上,由于该实现有漏洞,会返回垃圾,如:00000000或者****
MAC ADDRESS
概念:可以使用手机Wifi或蓝牙的MAC地址作为设备标识。
Wifi Mac关键代码:
WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
String wlan_mac = wm.getConnectionInfo().getMacAddress();
蓝牙 Mac关键代码:
String bt_mac = BluetoothAdapter.getDefaultAdapter().getAddress();
不足:
1.如果设备没有支持WIFI的硬件,就返回null;
2.如果设备没有支持蓝牙的硬件,就返回null。
Sim Serial Number
概念:SIM卡的序列号。
关键代码:
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String SimSerialNumber = tm.getSimSerialNumber();
不足:
1.没有装Sim卡时,返回null;
2.对于CDMA设备,返回null。
Serial Number
概念:Android系统2.3版本以上可以获取硬件Serial Number。
关键代码:
String sn = android.os.Build.SERIAL;
优点:非手机设备也可以通过该接口获取ID。
ANDROID_ID
概念:当设备首次启动时,系统会随机生成一个64位的数字,并把这个数字以16进制字符串的形式保存下来。
关键代码:
String android_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
不足:
1.它在Android <=2.1 or Android >=2.3的版本是可靠、稳定的,但在2.2的版本并不是100%可靠的;
2.在主流厂商生产的设备上,有一个很经常的bug,就是每个设备都会产生相同的ANDROID_ID。
Installation ID : UUID
概念:该标识符无需访问设备的资源,也跟设备类型无关。这种标识符是通过在程序安装后第一次运行后生成一个ID实现的,但该标识跟设备唯一标识不一样,它会因为不同的应用程序而产生不同的ID,而不是设备唯一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();
}
}
不足:
1.当卸载应用后重新安装,返回值与之前的值不同。
DEVICE_ID:UUID
概念:为了实现在设备上更通用的获取设备唯一标识,我们可以实现这样的一个类,为每个设备产生唯一的UUID,以ANDROID_ID为基础,在获取失败时以TelephonyManager.getDeviceId()为备选方法,如果再失败,使用UUID的生成策略。
关键代码:
public class DeviceUuidFactory {
protected static final String PREFS_FILE = "device_id.xml";
protected static final String PREFS_DEVICE_ID = "device_id";
protected 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);
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();
}
}
}
}
}
public UUID getDeviceUuid() {
return uuid;
}
}