解决方案

Android 如何获取有效的DeviceId

seo靠我 2023-09-25 17:21:47

目录

前言官方唯一标识符建议使用广告 ID使用实例 ID 和 GUID不要使用 MAC 地址标识符特性常见用例和适用的标识符 解决方案DeviceIdANDROID_IDMac地址UUID补充 总结

前言SEO靠我

从 Android 10 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 特许权限才能访问设备的不可重置标识符(包含 IMEI 和序列号)。

而这个权限是系统权限,也就是说一SEO靠我般应用将无法再获取IMEI 和序列号

受影响的方法包括:

Build

getSerial()

TelephonyManager

getImei()getDeviceId()getMeid()getSimSeriSEO靠我alNumber()getSubscriberId()

如果您的应用没有该权限,但您仍尝试查询不可重置标识符的相关信息,则平台的响应会因目标 SDK 版本而异:

如果应用以 Android 10 或更高版SEO靠我本为目标平台,则会发生 SecurityException。如果应用以 Android 9(API 级别 28)或更低版本为目标平台,则相应方法会返回 null 或占位符数据(如果应用具有 READ_SEO靠我PHONE_STATE 权限)。否则,会发生 SecurityException。

google也给出了一个解决方案

许多使用场景都不需要不可重置的设备标识符。例如,如果您的应用将不可重置的设备标识符用于SEO靠我广告跟踪或用户分析目的,请为这些特定使用场景使用 Android 广告 ID。要了解详情,请参阅唯一标识符的最佳做法。

这里大部分方案对国内无效,比如广告ID,需要google play的服务,但是国内SEO靠我的手机上都阉割掉了。所以我们只能参考一些可用的方案。

官方唯一标识符建议

这部分我们一起来看官方唯一标识的建议

使用广告 ID

国内就不要考虑了,需要依赖google play服务

使用实例 ID 和 GUIDSEO靠我

只对单一应用有效,卸载了就变了,不可取。

不要使用 MAC 地址

MAC 地址具有全局唯一性,无法由用户重置,在恢复出厂设置后也不会变化。因此,一般不建议使用 MAC 地址进行任何形式的用户标识。运行 ASEO靠我ndroid 10(API 级别 29)和更高版本的设备会报告不是设备所有者应用的所有应用的随机化 MAC 地址。

在 Android 6.0(API 级别 23)到 Android 9(API 级别 SEO靠我28)中,无法通过第三方 API 使用 Wi-Fi 和蓝牙等本地设备 Mac 地址。WifiInfo.getMacAddress() 方法和 BluetoothAdapter.getDefaultAdSEO靠我apter().getAddress() 方法都返回02:00:00:00:00:00

此外,在 Android 6.0 到 Android 9 版本中,您还必须拥有下列权限,才能访问通过蓝牙和 WiSEO靠我-Fi 扫描获得的附近外部设备的 MAC 地址:

方法/属性所需权限WifiManager.getScanResults()ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOSEO靠我CATIONBluetoothDevice.ACTION_FOUNDACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATIONBluetoothLeScanner.stSEO靠我artScan(ScanCallback)ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION

所以,mac是仅次于DeviceId的靠谱的标识,不过androidSEO靠我 6.0之后获取不到了。不过有其他方法完善,见后面。

标识符特性

一堆废话

常见用例和适用的标识符

也是一堆废话,要么就是国内无法使用,不过提到了SSAID。

SSAID,即ANDROID_ID(SettingSEO靠我s.Secure.ANDROID_ID),在8.0系统迎来改变,具体如下:

对于在 OTA 之前安装到某个版本 Android 8.0(API 级别 26)的应用,除非在 OTA 后卸载并重新安装,否则SEO靠我 ANDROID_ID 的值将保持不变。要在 OTA 后在卸载期间保留值,开发者可以使用密钥/值备份关联旧值和新值。

对于安装在运行 Android 8.0 的设备上的应用,ANDROID_ID 的值现SEO靠我在将根据应用签署密钥和用户确定作用域。应用签署密钥、用户和设备的每个组合都具有唯一的 ANDROID_ID 值。因此,在相同设备上运行但具有不同签署密钥的应用将不会再看到相同的 Android ID(SEO靠我即使对于同一用户来说,也是如此)。

只要签署密钥相同(并且应用未在 OTA 之前安装到某个版本的 O),ANDROID_ID 的值在软件包卸载或重新安装时就不会发生变化。

即使系统更新导致软件包签署密钥发SEO靠我生变化,ANDROID_ID 的值也不会变化。

可以看到8.0之后ANDROID_ID是与应用签名关联的,同签名的应用共用相同的ANDROID_ID,而且卸载重装不会变化。

而8.0之前,ANDROID_SEO靠我ID是与设备关联的,当设备首次启动时,系统会随机生成一个64位的数字,并以16进制字符串的形式保存到手机系统中,当手机恢复出厂设置后,Android ID会被重置,这是Android ID与DevicSEO靠我e ID的主要区别。当然还有其他bug,比如有些厂家获取为null之类的。

所以,ANDROID_ID是可以考虑的选择之一,后面细说。

解决方案

想要一个行为获取稳定的DeviceId是不可能的,我们需要多SEO靠我个行为结合处理。

DeviceId

首先就是传统的DeviceId,在Android 10一下还是很稳定的。

ANDROID_ID

在Android 8.0之后,就可以考虑用ANDROID_ID来代替DeviSEO靠我ceId了。

Settings.System.getString(BaseApp.getAppContext().getContentResolver(), Settings.Secure.ANDROISEO靠我D_ID);

这样可以做一个版本判断,低于10.0(或8.0)获取DeviceId,否则获取ANDROID_ID

Mac地址

如果上面两步获取的还是null,那么可以使用mac地址,但是mac由于6.0之后SEO靠我无法通过WifiInfo.getMacAddress()获取了,所以我们需要处理一下,代码如下:

public static String getMac(Context context) {StringSEO靠我 mac = "";if (context == null) {return mac;}if (Build.VERSION.SDK_INT < 23) {mac = getMacBySystemIntSEO靠我erface(context);} else {mac = getMacByJavaAPI();if (TextUtils.isEmpty(mac)){mac = getMacBySystemInteSEO靠我rface(context);}}return mac;}@TargetApi(9) private static String getMacByJavaAPI() {try {EnuSEO靠我meration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();while (interfaces.haSEO靠我sMoreElements()) {NetworkInterface netInterface = interfaces.nextElement();if ("wlan0".equals(netIntSEO靠我erface.getName()) || "eth0".equals(netInterface.getName())) {byte[] addr = netInterface.getHardwareASEO靠我ddress();if (addr == null || addr.length == 0) {return null;}StringBuilder buf = new StringBuilder()SEO靠我;for (byte b : addr) {buf.append(String.format("%02X:", b));}if (buf.length() > 0) {buf.deleteCharAtSEO靠我(buf.length() - 1);}return buf.toString().toLowerCase(Locale.getDefault());}}} catch (Throwable e) {SEO靠我}return null; }private static String getMacBySystemInterface(Context context) {if (context =SEO靠我= null) {return "";}try {WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVSEO靠我ICE);if (checkPermission(context, Manifest.permission.ACCESS_WIFI_STATE)) {WifiInfo info = wifi.getCSEO靠我onnectionInfo();return info.getMacAddress();} else {return "";}} catch (Throwable e) {return "";} SEO靠我 }

可以看到6.0即23以下直接获取,否则先通过NetworkInterface获取,获取不到再通过原方法获取。

目前来看这一步还是能稳定获取的。

UUID

兜底行为。因为需要我们手动生成,且每次SEO靠我生成的都不一样。

UUID.randomUUID().toString()

所以必须生成一次保存起来。这样就有一个问题,如果保存到应用内部存储,卸载后重装一定要重新生成,这样就无法判断是同一设备了。

所以最SEO靠我好将其保存到外部存储,保证卸载重装后还能读取到上次的值。

这样一般情况下是最稳定的,除非手动删除该文件。

所以最好的方案,就是将上面四个方案融合在一起,一个个兜底。目前来看,各手机厂商的指导方案也就这几个SEO靠我方案。

补充

除了上面的方案,还有移动安全联盟(信通院牵头)提供的sdk,可以获取几种设备标识符,大部分国内厂商都支持。

不过需要申请使用,还没测试过。

总结

通过上面分析可以看到,官方确实给出了不少替代方案,SEO靠我但是大部分都由于国内的限制而无法使用。所以国内基本上都是通过依次获取DeviceId、ANDROID_ID、MAC、UUID的方式来得到一个唯一id,流程大致如下:

#mermaid-svg-XtgtGSEO靠我gE8S0ilzScY {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-SEO靠我svg-XtgtGgE8S0ilzScY .error-icon{fill:#552222;}#mermaid-svg-XtgtGgE8S0ilzScY .error-text{fill:#55222SEO靠我2;stroke:#552222;}#mermaid-svg-XtgtGgE8S0ilzScY .edge-thickness-normal{stroke-width:2px;}#mermaid-svSEO靠我g-XtgtGgE8S0ilzScY .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XtgtGgE8S0ilzScY .edge-patSEO靠我tern-solid{stroke-dasharray:0;}#mermaid-svg-XtgtGgE8S0ilzScY .edge-pattern-dashed{stroke-dasharray:3SEO靠我;}#mermaid-svg-XtgtGgE8S0ilzScY .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XtgtGgE8S0ilzSSEO靠我cY .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XtgtGgE8S0ilzScY .marker.cross{stroke:#333333;}SEO靠我#mermaid-svg-XtgtGgE8S0ilzScY svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16pxSEO靠我;}#mermaid-svg-XtgtGgE8S0ilzScY .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#33SEO靠我3;}#mermaid-svg-XtgtGgE8S0ilzScY .cluster-label text{fill:#333;}#mermaid-svg-XtgtGgE8S0ilzScY .clustSEO靠我er-label span{color:#333;}#mermaid-svg-XtgtGgE8S0ilzScY .label text,#mermaid-svg-XtgtGgE8S0ilzScY spSEO靠我an{fill:#333;color:#333;}#mermaid-svg-XtgtGgE8S0ilzScY .node rect,#mermaid-svg-XtgtGgE8S0ilzScY .nodSEO靠我e circle,#mermaid-svg-XtgtGgE8S0ilzScY .node ellipse,#mermaid-svg-XtgtGgE8S0ilzScY .node polygon,#meSEO靠我rmaid-svg-XtgtGgE8S0ilzScY .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XtgSEO靠我tGgE8S0ilzScY .node .label{text-align:center;}#mermaid-svg-XtgtGgE8S0ilzScY .node.clickable{cursor:pSEO靠我ointer;}#mermaid-svg-XtgtGgE8S0ilzScY .arrowheadPath{fill:#333333;}#mermaid-svg-XtgtGgE8S0ilzScY .edSEO靠我gePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XtgtGgE8S0ilzScY .flowchart-link{strokeSEO靠我:#333333;fill:none;}#mermaid-svg-XtgtGgE8S0ilzScY .edgeLabel{background-color:#e8e8e8;text-align:cenSEO靠我ter;}#mermaid-svg-XtgtGgE8S0ilzScY .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8SEO靠我;}#mermaid-svg-XtgtGgE8S0ilzScY .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaidSEO靠我-svg-XtgtGgE8S0ilzScY .cluster text{fill:#333;}#mermaid-svg-XtgtGgE8S0ilzScY .cluster span{color:#33SEO靠我3;}#mermaid-svg-XtgtGgE8S0ilzScY div.mermaidTooltip{position:absolute;text-align:center;max-width:20SEO靠我0px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80SEO靠我, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}SEO靠我#mermaid-svg-XtgtGgE8S0ilzScY :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} SEO靠我不存在 不存在 不存在 存在 存在 存在 DeviceId? ANDROID_ID? MAC? 生成UUID 返回

你可能感兴趣:

Android 13发布,一起来看看有哪些新功能

详细解读Android中SEO靠我的事件分发机制

“SEO靠我”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与 我们联系删除或处理,客服邮箱:html5sh@163.com,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同 其观点或证实其内容的真实性。

网站备案号:浙ICP备17034767号-2