Android
设备用来唯一标示用户或设备的方法很多,没有统一的完美的方案。
有以下常用方案:
- IMEI/MEID
- ANDROID_ID
- Mac address
- Serial number
- Installation / GUID
IMEI/MEID
介绍
下面是维基百科上IMEI的介绍:
国际移动设备识别码(International Mobile Equipment Identity,IMEI),即通常所说的手机序列号、手机“串号”,用于在移动电话网络中识别每一部独立的手机等行动通讯装置,相当于移动电话的身份证。序列号共有15位数字,前6位(TAC)是型号核准号码,代表手机类型。接着2位(FAC)是最后装配号,代表产地。后6位(SNR)是串号,代表生产顺序号。最后1位(SP)一般为0,是检验码,备用。国际移动设备识别码一般贴于机身背面与外包装上,同时也存在于手机内存中,通过输入*#06#即可查询。
下面是百度百科里MEID的介绍:
MEID 移动设备识别码(Mobile Equipment Identifier)是CDMA手机的身份识别码,也是每台CDMA手机或通讯平板唯一的识别码。通过这个识别码,网络端可以对该手机进行跟踪和监管。用于CDMA制式的手机。MEID的数字范围是十六进制的,和IMEI的格式类似。
MEID's are also manged by the TIA. These are 56 bits long, and like ESN's, identify the manufacturer of a mobile device as well as the serial number assigned to the device by that manufacturer.The MEID consists of 32 bits to specify the manufacturer and 24 bits to specify the serial number: The first 4 bits of the manufacturer code are "reserved," and restricted to just a few values. There can also be a 4 bit "check digit" appended to the end, but this is not transmitted between the mobile device and the CDMA system (according to 3GPP2 S.R0048-A) and is not common to see.
获取
Android
中获取IMEI
的方法,首先需要在AndroidManifest.xml
文件中增加android.permission.READ_PHONE_STATE
权限:<manifest ...>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<application ...>
...
</application>
</manifest>
然后获取
IMEI
:final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
final String imei = tm.getDeviceId();
我们看下
TelephonyManager
中的getDeviceId
方法:/**
* Returns the unique device ID, for example, the IMEI for GSM and the MEID
* or ESN for CDMA phones. Return null if device ID is not available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getDeviceId();
下面是
API level 23
新增的方法:/**
* Returns the unique device ID of a subscription, for example, the IMEI for
* GSM and the MEID for CDMA phones. Return null if device ID is not available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
* @param slotId of which deviceID is returned
*/
public String getDeviceId(int slotId);
这两个接口可以返回
GSM
手机的IMEI
或者CDMA
手机的MEID
。slotId
是卡槽编号。
这两个接口在
API level O
中都标记为@Deprecated
,取而代之的是如下接口:/**
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getImei();
/**
* Returns the IMEI (International Mobile Equipment Identity). Return null if IMEI is not
* available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
* @param slotIndex of which IMEI is returned
*/
public String getImei(int slotIndex);
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getMeid();
/**
* Returns the MEID (Mobile Equipment Identifier). Return null if MEID is not available.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
* @param slotIndex of which MEID is returned
*/
public String getMeid(int slotIndex);
存在的问题
- 需要
android.permission.READ_PHONE_STATE
权限,用户可以禁止授权给应用 - 非手机设备没有
IMEI/MEID
IMEI/MEID
理论上应该没有重复,实际却不是这样的,有些厂商生产的设备会有重复
ANDROID_ID
下面是
ANDROID_ID
的解释:A 64-bit number (as a hex string) that is randomly generated when the user first sets up the device and should remain constant for the lifetime of the user's device. The value may change if a factory reset is performed on the device.
获取
import android.provider.Settings.Secure;
final String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
存在的问题
- 设备重置后会重新生成
ANDROID_ID
- 部分厂商的设备存在
ANDROID_ID
重复的情况,同样不是绝对可靠 - Android O 版本中,对于设备上的每个应用和用户,都有不同的
ANDROID_ID
Mac address
mac
地址或蓝牙地址也可以用作设备标识获取
获取
mac
地址需要android.permission.ACCESS_WIFI_STATE
权限:<manifest ...>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application ...>
...
</application>
</manifest>
获取
mac
代码:String mac = null;
final WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (wifiManager != null) {
final WifiInfo info = wifiManager.getConnectionInfo();
if (info != null) {
mac = info.getMacAddress();
}
}
存在的问题
下面是 Android 官网的说明:
MAC 地址具有全局唯一性,无法由用户重置,在恢复出厂设置后也不会发生变化。一般不建议使用 MAC 地址进行任何形式的用户标识。因此,从 Android M 开始,无法再通过第三方 API 获得本地设备 MAC 地址(例如,WLAN 和蓝牙)。WifiInfo.getMacAddress()
方法和BluetoothAdapter.getDefaultAdapter().getAddress()
方法都会返回 02:00:00:00:00:00。
- Android M开始无法获取 Mac 地址
- 没有 WIFI 的设备无法获取
- Wifi 没有打开时也无法获取 Mac 地址
Serial number
获取
final String sn = android.os.Build.SERIAL;
这是
API level 9
添加的,在 Android O 中这个字段被置为"unknown",需要使用android.os.Build.getSerial()
方法来获取:public static getSerial();
存在的问题
- Android O 中,
android.os.Build.SERIAL
标记为@deprecated,使用android.os.Build.getSerial()
需要android.permission.READ_PHONE_STATE
权限
Installation ID / GUID
获取
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();
}
}
存在的问题
应用卸载重装,或者清理缓存,会清除掉这个标识,下次只能重新生成一个新的
UUID
字符串标识
没有评论:
发表评论