|
先来看看几种比较单一的方式:
IMEI
方式:TelephonyManager.getDeviceId():
问题
范围:只能支持拥有通话功能的设备,对于平板不可以。
持久性:返厂,数据擦除的时候不彻底,保留了原来的标识。
权限:需要权限:android.permission.READ_PHONE_STATE
bug: 有些厂家的实现有bug,返回一些不可用的数据
Mac地址
ACCESS_WIFI_STATE权限
有些设备没有WiFi,或者蓝牙,就不可以,如果WiFi没有打开,硬件也不会返回Mac地址,不建议使用
ANDROID_ID
2.2(Froyo,8)版本系统会不可信,来自主要生产厂商的主流手机,至少有一个普遍发现的bug,这些有问题的手机相同的ANDROID_ID: 9774d56d682e549c
但是如果返厂的手机,或者被root的手机,可能会变
Serial Number
从Android 2.3 (“Gingerbread”)开始可用,可以通过android.os.Build.SERIAL获取,对于没有通话功能的设备,它会
返回一个唯一的device ID,
以下几个是stackoverflow上评论较多的几个,没贴完,还有其他,综合的,用到以上的部分方式:
地址:http://stackoverflow.com/questions/2785485/is-there-a-unique-android-device-id
google官方的相关博客:http://android-developers.blogspot.com/2011/03/identifying-app-installations.html
有兴趣的朋友可以再仔细看看
支持率比较高的(支持票数157):androidID --> 剔除2.2版本(API 8)中有问题的手机,使用UUID替代
-
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 static volatile 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) {
-
-
-
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);
-
}
-
-
prefs.edit()
-
.putString(PREFS_DEVICE_ID, uuid.toString())
-
.commit();
-
}
-
}
-
}
-
}
-
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
public UUID getDeviceUuid() {
-
return uuid;
-
}
-
}
根据版本进行判断的方式:Serial序列号-->UUID (支持数31)
通过Serial 即可,在覆盖率上,你已经成功的获得了98.4%的用户,剩下的1.6%的用户系统是在9 以下的。
通过AndroidID获取,前面已经说过,在8上,有些商家的手机会有一些bug,返回相同的AndroidID,如果Serial和AndroidID都不行
-
-
-
-
-
public static String getUniquePsuedoID()
-
{
-
-
-
-
-
-
-
-
-
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);
-
-
-
-
-
-
-
String serial = null;
-
try
-
{
-
serial = android.os.Build.class.getField("SERIAL").get(null).toString();
-
-
-
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
-
}
-
catch (Exception e)
-
{
-
-
serial = "serial";
-
}
-
-
-
-
-
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
-
}
不用READ_PHONE_STATE权限直接获取ROM信息的方式:(支持率较低 16)
-
String m_szDevIDShort = "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 ;
最后贴上自己在项目中用的:
-
public static String getDeviceId(Context context) {
-
String deviceId = "";
-
<span style="white-space:pre"> </span>if (deviceId != null && !"".equals(deviceId)) {
-
<span style="white-space:pre"> </span>return deviceId;
-
<span style="white-space:pre"> </span>}
-
if (deviceId == null || "".equals(deviceId)) {
-
try {
-
deviceId = getLocalMac(context).replace(":", "");
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
if (deviceId == null || "".equals(deviceId)) {
-
try {
-
deviceId = getAndroidId(context);
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
if (deviceId == null || "".equals(deviceId)) {
-
-
if (deviceId == null || "".equals(deviceId)) {
-
UUID uuid = UUID.randomUUID();
-
deviceId = uuid.toString().replace("-", "");
-
writeDeviceID(deviceId);
-
}
-
}
-
return deviceId;
-
}
-
-
private static String getIMIEStatus(Context context) {
-
TelephonyManager tm = (TelephonyManager) context
-
.getSystemService(Context.TELEPHONY_SERVICE);
-
String deviceId = tm.getDeviceId();
-
return deviceId;
-
}
-
-
-
private static String getLocalMac(Context context) {
-
WifiManager wifi = (WifiManager) context
-
.getSystemService(Context.WIFI_SERVICE);
-
WifiInfo info = wifi.getConnectionInfo();
-
return info.getMacAddress();
-
}
-
-
-
private static String getAndroidId(Context context) {
-
String androidId = Settings.Secure.getString(
-
context.getContentResolver(), Settings.Secure.ANDROID_ID);
-
return androidId;
-
}
-
-
public static void saveDeviceID(String str) {
-
try {
-
FileOutputStream fos = new FileOutputStream(file);
-
Writer out = new OutputStreamWriter(fos, "UTF-8");
-
out.write(str);
-
out.close();
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
-
public static String readDeviceID() {
-
StringBuffer buffer = new StringBuffer();
-
try {
-
FileInputStream fis = new FileInputStream(file);
-
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
-
Reader in = new BufferedReader(isr);
-
int i;
-
while ((i = in.read()) > -1) {
-
buffer.append((char) i);
-
}
-
in.close();
-
return buffer.toString();
-
} catch (IOException e) {
-
e.printStackTrace();
-
return null;
-
}
-
}
对于获取设备唯一ID并没有绝对的方案,这一点在android的官方博客中也提到了,不过以上几种方案,应该可以满足平时的需求,大家可以选择其中自己认为比较好的,用于自己的项目中。不知道其他朋友在项目中是如何处理的,欢迎交流讨论。 |