它刚刚曝光 iOS 5 iOS 5 并且在iOS 7及更高版本中无法使用 . 似乎没有替代方法或 property 可用或即将出现 .
我们的许多现有应用程序都严格依赖此属性来唯一标识特定设备 . 我们如何处理这个问题呢?
来自the documentation in 2011-2012的建议是:
特殊注意事项请勿使用uniqueIdentifier属性 . 要创建特定于应用程序的唯一标识符,可以调用CFUUIDCreate函数来创建UUID,并使用NSUserDefaults类将其写入默认数据库 .
但是,如果用户卸载并重新安装应用程序,则此值将不同 .
30 回答
看起来对于iOS 6,Apple建议你使用the NSUUID class .
从UIDevice docs中的
uniqueIdentifier
属性消息:如果用户卸载并重新安装应用程序,则
CFUUIDCreate
创建的UUID是唯一的:您每次都会获得一个新的 .但你可能希望它不是唯一的,我 . 即当用户卸载并重新安装应用程序时,它应该保持不变 . 这需要一些努力,因为最可靠的每设备标识符似乎是MAC地址 . 您可以查询MAC并将其用作UUID .
编辑:当然,需要始终查询同一界面的MAC . 我想最好的选择是使用en0 . 即使接口没有IP /关闭,MAC也始终存在 .
Edit 2: 正如其他人所指出的,iOS 6以来的首选解决方案是-[UIDevice identifierForVendor] . 在大多数情况下,您应该能够将其用作旧版
-[UIDevice uniqueIdentifier]
的替代品(但是第一次启动应用时创建的UUID是Apple似乎希望您使用的) .编辑3:所以这个主要观点不会在评论噪声中丢失:不要使用MAC作为UUID,使用MAC创建哈希 . 每次都会创建相同的结果,即使在重新安装和应用程序中也是如此(如果散列以相同的方式完成) . 无论如何,现在(2013)除了在iOS <6.0上需要“稳定”的设备标识符之外,这是不再需要的 .
Edit 4: 在iOS 7中,Apple现在总是在查询MAC时返回固定值,以专门阻止MAC作为ID方案的基础 . 所以你现在真的应该使用-[UIDevice identifierForVendor]或创建一个每安装UUID .
您已经可以使用Apple的替代品
UDID
. 善良的家伙gekitz在UIDevice
上写了类别,它会根据设备的mac-address和bundle identifier生成某种UDID
.你可以在github上找到代码
可以提供帮助:使用以下代码,除了擦除(格式化)您的设备外,它始终是唯一的 .
我也会建议从
uniqueIdentifier
切换到this open source library(真正的2个简单类别),利用设备的MAC地址和应用程序包标识符在您的应用程序中生成可用作UDID替换的唯一ID .请记住,与UDID不同,这个数字对于每个应用都会有所不同 .
您只需导入包含的
NSString
和UIDevice
类别并像这样调用[[UIDevice currentDevice] uniqueDeviceIdentifier]
:你可以在Github上找到它:
UIDevice with UniqueIdentifier for iOS 5
以下是类别(只是.m文件 - 检查标头的github项目):
您可以通过以下代码实现:UIDevice-with-UniqueIdentifier-for-iOS-5
根据@moonlight提出的链接,我做了几次测试,似乎是最好的解决方案 . 正如@DarkDust所说,该方法会检查始终可用的
en0
.有两种选择:
uniqueDeviceIdentifier
(MAC CFBundleIdentifier的MD5)和
uniqueGlobalDeviceIdentifier
(MAC的MD5),它们总是返回相同的值 .在我完成的测试之下(使用真实设备):
希望它有用 .
EDIT:
正如其他人所指出的,iOS 7中的这个解决方案不再有用,因为
uniqueIdentifier
不再可用,现在查询MAC地址总是返回02:00:00:00:00:00看一下这个,
我们可以使用Keychain而不是
NSUserDefaults
类来存储由CFUUIDCreate
创建的UUID
.通过这种方式我们可以避免重新安装
UUID
娱乐,并获得相同的应用程序UUID
甚至用户卸载并重新安装 .UUID
将在用户重置设备时重新创建 .我用SFHFKeychainUtils尝试了这个方法,它就像一个魅力 .
创建自己的UUID,然后将其存储在Keychain中 . 因此,即使您的应用程序被卸载,它仍然存在 . 在许多情况下,即使用户在设备之间迁移(例如完全备份和还原到其他设备),它也会持续存在 .
实际上,只要您担心,它就会成为唯一的用户标识符 . (甚至比设备标识符更好) .
例:
我正在定义一个用于创建
UUID
的自定义方法:然后,您可以在应用程序首次启动时将其存储在
KEYCHAIN
中 . 因此,首次启动后,我们可以简单地从钥匙串使用它,无需重新生成它 . 使用Keychain存储的主要原因是:当您将UUID
设置为Keychain时,即使用户完全卸载App然后再次安装,它也会持续存在 . . 因此,这是存储它的永久方式,这意味着密钥将一直是唯一的 .On applictaion launch include the following code :
从sskeychain下载SSKeychain.m和.h文件,并将SSKeychain.m和.h文件拖到项目中,并将"Security.framework"添加到项目中 . 之后使用UUID只需使用:
也许你可以使用:
Apple的文档描述了identifierForVender,如下所示:
对于来自同一设备上运行的同一供应商的应用,此属性的值相同 . 对于来自不同供应商的同一设备上的应用程序以及不同供应商的不同设备上的应用程序,将返回不同的值 .
您可能需要考虑使用
OpenUDID
,它是已弃用的UDID
的替代品 .基本上,要匹配
UDID
,需要以下功能:唯一或足够独特(低概率碰撞可能是非常可接受的)
持久性重新启动,恢复,卸载
适用于不同供应商的应用程序(通过CPI网络获取用户非常有用) -
OpenUDID
实现了上述功能,甚至还有一个内置的Opt-Out机制供以后考虑 .检查http://OpenUDID.org它指向相应的GitHub . 希望这可以帮助!
作为旁注,我会回避任何MAC地址替代方案 . 虽然MAC地址看起来像一个诱人的通用解决方案,但请确保这种低悬的水果中毒 . MAC地址非常敏感,Apple甚至可以拒绝访问此地址,甚至可以说“提交此应用程序”...... MAC网络地址用于验证私有设备(WLAN)或其他虚拟专用设备上的某些设备网络(VPN) . ..它比以前的UDID更敏感!
我相信苹果公司已经让很多人对这种变化感到恼火 . 我为iOS开发了一个bookkeeping app,并提供了一个在线服务来同步在不同设备上进行的更改 . 该服务维护所有设备的数据库以及需要传播给它们的更改 . 因此,它使用UIDevice uniqueIdentifier来跟踪设备,以及它的 Value ,这是我的想法 .
生成UUID并以用户默认值存储?不好,因为当用户删除应用程序时,这不会持续存在 . 如果稍后再次安装,则在线服务不应创建新设备记录,这会浪费服务器上的资源并提供包含相同设备的设备列表两次或更多次 . 如果他们重新安装应用程序,用户会看到列出多个“Bob的iPhone” .
生成UUID并存储在钥匙串中?这是我的计划,因为它甚至在卸载应用程序时仍然存在 . 但是,当将iTunes备份恢复到新的iOS设备时,如果备份已加密,则会传输钥匙串 . 如果旧设备和新设备都在使用中,这可能导致两个设备包含相同的设备ID . 这些应该在在线服务中列为两个设备,即使设备名称相同 .
生成MAC地址和包ID的哈希值?这看起来是我需要的最佳解决方案 . 通过使用包ID进行散列,生成的设备ID不会启用跨应用程序跟踪设备,并且我获得了应用设备组合的唯一ID .
它's interesting to note that Apple'自己的文档是指通过计算系统MAC地址的散列加上包ID和版本来验证 Mac App Store收据 . 所以这似乎是政策所允许的,无论是通过我还不知道的应用评论 .
MAC地址可能是欺骗性的,这使得这种方法无法将内容绑定到特定用户或实现黑名单等安全功能 .
经过一些进一步的研究后,在我看来,我们现在还没有一个合适的选择 . 我真的希望苹果公司能够重新考虑他们的决定 .
也许向Apple发送关于此主题的电子邮件和/或提交错误/功能请求可能是一个好主意,因为他们可能甚至不知道开发人员的全部后果 .
iOS 6中引入的
UIDevice identifierForVendor
可用于您的目的 .identifierForVendor
是一个字母数字字符串,用于唯一标识应用程序供应商的设备 . (只读)对于来自同一设备上运行的同一供应商的应用,此属性的值相同 . 对于来自不同供应商的同一设备上的应用程序以及供应商的不同设备上的应用程序,将返回不同的值 .
适用于iOS 6.0及更高版本,并在
UIDevice.h
中声明对于iOS 5,请参阅此链接UIDevice-with-UniqueIdentifier-for-iOS-5
使用上面提到的SSKeychain和代码 . 这是复制/粘贴的代码(添加SSKeychain模块):
}
以下代码有助于获取UDID:
这是我用来获取iOS 5和iOS 6,7的ID的代码:
从iOS 6开始,我们有
NSUUID
类符合RFC4122Apple Link:apple_ref for NSUUID
iOS 11引入了DeviceCheck框架 . 它具有全面的解决方案,可以唯一识别设备 .
您可以使用
这在所有应用中都是独一无二的 .
Apple在iOS 11中添加了一个名为DeviceCheck的新框架,它可以帮助您轻松获取唯一标识符 . 阅读此表格了解更多信息 . https://medium.com/@santoshbotre01/unique-identifier-for-the-ios-devices-590bb778290d
如果有人在找到替代方案时偶然发现了这个问题 . 我在
IDManager
类中遵循了这种方法,这是来自不同解决方案的集合 . KeyChainUtil是一个从keychain读取的包装器 . 您还可以将hashed MAC address
用作一种唯一ID .我们可以将 identifierForVendor 用于ios7,
--Important Note ---
UDID和identifierForVendor是不同的:---
从iOS 7开始,Apple已将UDID隐藏在所有公共API中 . 任何以FFFF开头的UDID都是伪造的ID . 以前工作的“发送UDID”应用程序不能再用于收集测试设备的UDID . (叹!)
当设备连接到XCode(在管理器中),以及设备连接到iTunes时,会显示UDID(尽管您必须单击“序列号”才能显示标识符) .
如果您需要获取要添加到配置文件的设备的UDID,并且无法在XCode中自行完成,则必须完成从iTunes复制/粘贴它的步骤 .
Is there a way since (iOS 7's release) to get the UDID without using iTunes on a PC/Mac?
我也有一些问题,解决方案很简单:
A not perfect but one of the best and closest alternative to UDID (in Swift using iOS 8.1 and Xcode 6.1):
生成随机UUID
And use KeychainWrapper library:
将字符串值添加到钥匙串:
从钥匙串中检索字符串值:
从钥匙串中删除字符串值:
此解决方案使用钥匙串,因此即使在卸载并重新安装应用程序之后,存储在钥匙串中的记录也将保留 . 删除此记录的唯一方法是重置设备的所有内容和设置 . 这就是为什么我提到这种替代解决方案并不完美,但仍然是使用Swift在iOS 8.1上替换UDID的最佳解决方案之一 .
获取UDID的一种工作方式:
在应用程序内部启动Web服务器,其中包含两个页面:一个应返回特制的MobileConfiguration配置文件,另一个应收集你做了 . 更多信息here,here和here .
您从应用程序内部打开Mobile Safari中的第一页,它会将您重定向到Settings.app,要求安装配置文件 . 安装配置文件后,UDID将发送到第二个网页,您可以从应用程序内部访问它 . (Settings.app具有所有必要的权利和不同的沙盒规则) .
使用RoutingHTTPServer的示例:
以下是
udid.mobileconfig
的内容:配置文件安装将失败(我没有打算实现预期的响应,请参阅documentation),但应用程序将获得正确的UDID . 你也应该sign the mobileconfig .
NSLog(@“%@”,[[UIDevice currentDevice] identifierForVendor]);
对于Swift 3.0,请使用以下代码 .