android ios 如何获取设备唯一id

本文探讨了在iOS和Android平台上获取设备唯一标识的方法。针对隐私保护趋势,介绍了无需特殊权限即可实现设备标识的技术方案,并提供了uniapp及flutter插件实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


title: android ios 如何获取设备唯一id
tags: android,ios,unique_id, flutter, uniapp
keywords: unique_id,iOS, uniapp插件, android,设备id,设备唯一标识,unique_device_id,flutter插件
description: 设备唯一id如何获取,安卓获取设备唯一标识;iOS设备唯一标识

前言

设备id,也就是和设备可以一一对应,并且每次获取都是相同的这么一个字符串,在早些年,系统api是开放的,可以直接获取到唯一的设备标识,这些设备标识往往是和设备硬件绑定的,这样一来,设备id就是永远固定的,除非更换了硬件,但是随着现在对于个人隐私保护的重视,系统api已经不能获取到唯一标识,那么我们就只能另外想办法了。获取设备id的目的无非也就以下几点:

  • 统计,统计DAU等
  • 业务需要,这类APP一般都是根据个人喜好来推送内容,恰恰是有违隐私保护政策
  • 风险控制,防止薅羊毛等刷注册行为

随着工信部或应用市场合规整改通知的发布,对于个人隐私保护已经非常严格,相信不少的人都收到以下警告:

  • 违规收集个人信息
  • 强制、频繁、过度索取权限

分析

对于iOS,虽然官方api也去掉了,但是还是有identifierForVendor可以将就使用,实在不行那就自己生产一个uuid保存在keychain里,这样就自己生成uuid来实现设备标识;这里要说的是安卓可以用相同的思路来实现,但是由于安卓没有keychain类似的实现,所以只能自己生成后保存到SDK卡,这样才能保证APP卸载之后数据不丢失,但是这样又涉及到获取SDK权限,用户:你TM又想瞎存啥东西?所以我们应该尽量避免需要权限的做法。

安卓唯一id的文章网上已经泛滥了,但是大致也就那么几种方式,在经过筛选之后,我个人觉得如果我们要在不需要权限的情况下获取,那么我们只能尽量保证准确性,很难做到百分百,另外有种思路就是说把能获取到的能标识的数据都获取,然后自己服务器保存起来,每次获取之后对比,有几个数据相同则表示是同一设备,这种方式需要服务器来保存,还需要一个策略来判断,除了繁琐点,其实还是不错的。

借鉴于[is-there-a-unique-android-device-id](https://stackoverflow.com/questions/2785485/is-there-a-unique-android-device-id),乐观一点话会发现其实通过 Build.BOARD Build.BRAND Build.CPU_ABI 等等参数来生成的序列还是很大程度能标识设备,如果Build. SERIAL能获取成功,那么将会很大可能能区分,如果Build. SERIAL不能获取成功,那么我们可以暂时使用Android ID来代替Build. SERIAL,虽然Android ID会在用户刷机或者恢复出厂设置时变更,但是毕竟这样做的人不会太多。

基于以上思路,于是安卓代码就长这样:

	private String getUniquePsuedoID() {
        // If all else fails, if the user does have lower than API 9 (lower
        // than Gingerbread), has reset their device or 'Secure.ANDROID_ID'
        // returns 'null', then simply the ID returned will be solely based
        // off their Android device information. This is where the collisions
        // can happen.
        // Thanks http://www.pocketmagic.net/?p=1662!
        // Try not to use DISPLAY, HOST or ID - these items could change.
        // If there are collisions, there will be overlapping data
        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);

        // Thanks to @Roman SL!
        // https://stackoverflow.com/a/4789483/950427
        // Only devices with API >= 9 have android.os.Build.SERIAL
        // http://developer.android.com/reference/android/os/Build.html#SERIAL
        // If a user upgrades software or roots their device, there will be a duplicate entry
        String serial = null;
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                serial = android.os.Build.getSerial();
            } else {
                serial = Build.SERIAL;
            }
            // Go ahead and return the serial for api => 9
            return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
        } catch (Exception exception) {
            // String needs to be initialized
            final String androidId = "" + android.provider.Settings.Secure.getString(_flutterPluginBinding.getApplicationContext().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
            serial = androidId;
        }

        // if Build.SERIAL get successfuly, the 'id' is unique very likely, if not, we use androidId to guarante 'id' to be unique as possible
        // without any permissions


        // Thanks @Joe!
        // https://stackoverflow.com/a/2853253/950427
        // Finally, combine the values we have found by using the UUID class to create a unique identifier
        return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
    }

源码

考虑到现在跨平台的流行,笔者将实现封装成了uniapp和flutter插件,可以在uniapp开发跨平台APP和flutter开发中使用

### 获取唯一设备ID的挑战 在开发过程中,获取一个能够唯一标识设备ID是一个常见的需求。然而,在AndroidiOS平台上,由于隐私政策技术限制的影响,这一目标变得愈发困难。 #### Android 平台上的解决方案 在Android平台上,虽然存在多种可能用于识别设备的方式,但由于系统更新以及对用户隐私保护的要求日益严格,许多传统方法已经不再适用[^1]。例如,IMEI、MAC地址Android ID曾被广泛使用,但这些方式要么受到权限限制,要么无法满足跨应用的一致性稳定性要求[^2]。 一种推荐的做法是创建并存储自定义的应用级UUID作为设备标识符。这种方法可以确保即使操作系统版本发生变化或者硬件特性不可访问的情况下仍然有效: ```java public class DeviceIdManager { private static final String PREFS_FILE = "device_id.xml"; private static final String PREFS_DEVICE_ID = "device_id"; public static String getDeviceId(Context context) { SharedPreferences prefs = context.getSharedPreferences(PREFS_FILE, Context.MODE_PRIVATE); String deviceId = prefs.getString(PREFS_DEVICE_ID, null); if (deviceId == null) { deviceId = UUID.randomUUID().toString(); SharedPreferences.Editor editor = prefs.edit(); editor.putString(PREFS_DEVICE_ID, deviceId); editor.apply(); } return deviceId; } } ``` 此代码片段展示了如何利用SharedPreferences保存一个随机生成的UUID,并将其作为设备ID返回。 #### iOS 平台上的解决方案 对于iOS来说,苹果公司出于隐私考虑早已停止支持UDID等可以直接追踪用户的标识方案。目前官方建议使用的Identifier For Vendor(IDFV),它由App Store分配给同一供应商下的所有应用程序共享同一个值直到卸载最后一个关联程序为止;还有Advertising Identifier(IDFA),主要用于广告目的且允许用户重置或禁用其跟踪功能。 如果需要更持久可靠的解决办法,则可以通过Keychain服务来储存自行产生的GUID形式的数据串当作专属标志码: ```swift import UIKit import Security func save(key: String, data: Data) -> OSStatus { let query: [String : Any] = [ kSecClass as String : kSecClassGenericPassword, kSecAttrAccount as String : key, kSecValueData as String : data ] SecItemDelete(query as CFDictionary) return SecItemAdd(query as CFDictionary, nil) } func load(key: String) -> Data? { let query: [String : Any] = [ kSecClass as String : kSecClassGenericPassword, kSecAttrAccount as String : key, kSecReturnData as String : true, kSecMatchLimit as String : kSecMatchLimitOne ] var result: AnyObject? SecItemCopyMatching(query as CFDictionary, &result) return result as? Data } let deviceIDKey = "com.example.deviceid" if let storedData = load(key: deviceIDKey), let id = NSString(data:storedData, encoding:String.Encoding.utf8.rawValue){ print(id) } else{ let newID = NSUUID().uuidString.data(using:.utf8)! _ = save(key: deviceIDKey, data:newID) print(String(data:newID,encoding:.utf8)!) } ``` 上述Swift代码实现了基于Keychain的安全数据存取机制,从而达到长期保留特定字符串的目的。 ### 结论 综上所述,在当前环境下无论是Android还是iOS都无法简单直接地获得完全意义上的永久型物理装置编号。因此采用软件层面构建逻辑实体号成为主流趋势之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

huhansome

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值