1、IMEI 等设备标识符已经被认定为用户隐私的一部分,在非必要的场景获取甚至频繁获取 IMEI,会被认定为违规获取用户信息的行为;
2、 Android 10 开始,应用无法获取 IMEI、MAC 等设备唯一标识(申请 READ_PRIVILEGED_PHONE_STATE 权限后也可以获取,但这个权限只有系统应用能够获取)。如果应用强行获取,则会获取到 null 信息或发生 SecurityException(取决于 targetSdkVersion
);
3、为了解决这个问题,国家相关部委成立了移动安全联盟 MSA,制定了一套《移动智能终端补充设备标识体系》。因为其中最重要的一个标识符是 OAID 匿名设备标识符,因此也有人把这个体系简称为 OAID。
UUID 设备唯一标识符 是不依赖于这个体系的,它们在设备出厂时就固化到硬件信息上了,即使恢复出厂设置也不会重置;
OAID 匿名设备标识 是 UUID 的替代品,在终端首次启动时生成。同一设备的 OAID 相同,因此可以在多个应用之间共享,恢复出厂设置会重置 OAID;
VAID 开发者匿名设备标识符 是开发者维度的 ID,在应用安装时生成。同一设备上且同一开发者的所有应用 VAID 相同,其他情况 VAID 不同,重新安装应用会重置 VAID;
AAID 应用匿名设备标识符 是应用沙盘维度的 ID,在应用安装时生成。即使是同一设备且同一个开发者的应用,AAID 也不同,重新安装、清除用户数据会重置 AAID。
想要实现设备唯一,必须是由厂商支持,所以移动安全联盟的成员和专注于中国市场的厂商会率先支持(我使用的一加截止2020.5.6没有支持),华为、小米、OPPO、vivo、中兴、努比亚、魅族、联想、三星等设备厂商均将逐步支持(一些老的设备且没有经过系统更新的不支持)
走正常流程是根据 MSA 的要求,下载 SDK 和集成文档前需要注册一个企业账户,这一步按照指引提交相关信息和资料即可,一般 1~2 个工作日就可以审核通过。审核通过还得去商城申请APP的信息才能使用,下面说一种省去这些麻烦步骤,通过反射的方法 直接使用他们sdk生成唯一编号的方法,下面是代码。
如需获取sdk 关注公众号后 回复关键词 OAID 即可。
1、下载sdk之后配置到项目里
supplierconfig.json里只需给一个空结构就行,无需添加APP信息。
supplierconfig.json文件
{
"supplier":{
"vivo":{
},
"xiaomi":{
},
"huawei":{
},
"oppo":{
}
}
}
2、调用代码
public static boolean getID(Context context) {
try {
Class> refCus = Class.forName("com.bun.miitmdid.core.MdidSdkHelper");
Class> callback;
try {
// 1.0.10 版本
callback = Class.forName("com.bun.miitmdid.core.IIdentifierListener");
} catch (ClassNotFoundException e) {
// 1.0.23 版本
callback = Class.forName("com.bun.miitmdid.interfaces.IIdentifierListener");
}
final InnerIdSupplier mh = new InnerIdSupplier(context);
Object mObj = Proxy.newProxyInstance(context.getClassLoader(), new Class[]{callback}, mh);
Method initSdk = refCus.getDeclaredMethod("InitSdk", Context.class, boolean.class, callback);
int result = (int) initSdk.invoke(null, context, true, mObj);
return result == 0;
} catch (Throwable e) {
return false;
}
}
private static class InnerIdSupplier implements InvocationHandler {
Context context;
public InnerIdSupplier(Context context) {
this.context=context;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
try {
if ("OnSupport".equals(method.getName())) {
boolean isSupport = (boolean) objects[0];
if (isSupport) {
Object idSupplier = objects[1];
String oaid = (String) idSupplier.getClass().getDeclaredMethod("getOAID").invoke(idSupplier);
Log.e("唯一id",oaid+"");
Looper.prepare();
Toast.makeText(context,oaid,Toast.LENGTH_LONG).show();
Looper.loop();
// SpUtils.setString(Utils.getContext(), OAIDHelper.OAID, oaid);
}
return null;
}
return method.invoke(o, objects);
} catch (Throwable e) {
return null;
}
}
}
3、使用
在项目初始化的时候调用getID(this)方法,会在InnerIdSupplier 里边生成唯一id保存起来使用即可。
如需获取sdk 关注公众号后 回复关键词 OAID 即可。
关注我获取更多知识或者投稿