首页

时间和精神的房子
壹只iOS程序员的修行世界,欢迎来访

如果文章对您有所帮助
将是我最大的荣幸

iOS中的设备唯一标识

在 iOS7 之前,曾经有过很多获取设备唯一标识的方法。但是它们都先后被苹果禁止掉了。这些被禁止掉的包括 UDID、Mac 地址、OpenUDID。在 iOS 7 之后,我们可以选择的唯一标识有 IDFA、IDFV、DeviceToken、UUID 四种方案。他们各有利弊,下面对他们进行对比。

IDFA

IDFA(广告标识符)可以通过如下代码来获取。

[[[UIDevice currentDevice] advertisingIdentifier] UUIDString]

有如下几种情况下 IDFA 可能被重置。

  1. 重置系统(设置 -> 通用 -> 还原 -> 还原位置与隐私)
  2. 还原广告标识符(设置 -> 隐私 -> 广告 -> 还原广告标识符)
  3. iOS10 以下打开限制广告追踪(设置 -> 隐私 -> 广告 -> 限制广告追踪)

IDFA 在使用时需要注意如下几种情况。

  1. 在提交 App 的时候勾选对应的选项,不然可能遭到拒绝。
  2. 如果程序在后台运行,此时用户还原广告标识符,这时回到程序中并不会立即获得还原后的标识符。必须重新启动程序,才能获得还原后的广告标识符。
  3. 在 iOS10 以上打开限制广告追踪追踪后,只能获取到 0。

IDFV

IDFV(Vendor 标识符)可以通过如下代码来获取。

[[[UIDevice currentDevice] identifierForVendor] UUIDString]

Vendor 是指 Bundle ID 的前两段(com.company)。IDFV 只有在相同 Vendor 和相同设备里才具有唯一性。所以它不适合做不同 Vender 的 App 之前的唯一标识,但非常适合做相同 Vender 的 App 的唯一标识。不过,如果用户将属于此 Vender 的所有 App 卸载,IDFV 的值也会被重置。

DeviceToken

DeviceToken 需要使应用拥有推送功能才能获取,所以单独为了唯一标识而开启推送是不值得的。DeviceToken 能保证唯一性,但会被苹果修改。它的缺点是每次打开都需要有网络的情况下才能获取,而且苹果的推送服务偶尔也会出问题导致无法获取。在成功注册推送后可以通过如下代码获取返回的 DeviceToken。

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSString *deviceTokenString = [NSString stringWithFormat:@"%@", deviceToken];
    deviceTokenString = [deviceTokenString stringByReplacingOccurrencesOfString:@"<" withString:@""];
    deviceTokenString = [deviceTokenString stringByReplacingOccurrencesOfString:@">" withString:@""];
    deviceTokenString = [deviceTokenString stringByReplacingOccurrencesOfString:@" " withString:@""];
}

UUID

UUID(Universally Unique Identifier)是让分布式系统中的所有元素不需要通过服务器就能做到唯一性的标识符。每次获取 UUID 都能得到不同的值。正是因为这种特性,苹果建议使用 UUID 为 App 生成字符串并自己储存来实现唯一标识。这种方案下储存的值会在软件卸载重装后改变。

CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
NSString *uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuid);
CFRelease(uuid);

Keychina

上述唯一标识的方案都存在或多或少有被重置或者获取不到的可能。但是他们都可以与 Keychina 进行结合。Keychina 是独立于软件外可以用来存放账号密码的区域,它不会随着软件的卸载和系统重置而消失。Keychina 的特性结合 UUID 的特性已经能做到近乎完美的设备唯一标识。这也是现在大部分软件的做法。

而且你不用担心 Keychina 会被 iCloud 同步导致多个相同 iCloud 账号的不同设备拥有相同的唯一标识。只有 WiFi 密码和 Safari 表单等 Items 才会默认被同步,第三方 App 的 Items 默认是不同步的。如下是关于这个问题对苹果官方文档的引用。

The entire keychain is not synced. Some items are device-speci c, such as VPN identities, and shouldn’t leave the device. Only items with the attribute kSecAttrSynchronizable are synced. Apple has set this attribute for Safari user data (including user names, passwords, and credit card numbers), as well as Wi-Fi passwords.

Additionally, by default, keychain items added by third-party apps do not sync. Developers must set the kSecAttrSynchronizable when adding items to the keychain.

Keychain 的使用也很简单。增删改查四个 API 的如下所示。

SecItemAdd((__bridge CFDictionaryRef)query, NULL);
SecItemDelete((__bridge CFDictionaryRef)query);
SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)passwordData);
SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&resultData);

当储存信息时,主要有如下五个字段。

  1. kSecClass:种类
  2. kSecAttrAccount:账户
  3. kSecAttrService:位置
  4. kSecAttrLabel:注释
  5. kSecValueData:密码

Keychain 的使用可以参考本文的 Demo。你也可以借助用第三方 BCCKeychain (1200+ Star)来更方便和安全的使用 Keychain。当然如果你仅仅为了通过 Keychain 实现唯一标识,那也可以直接使用 FCUUID(800+ Start)。

参考资料

[简书] 钥匙串使用
[曾嵘] 在 iOS 7 中获取唯一标识符(UDID/UUID)
[简书] iOS-理解 : UDID、UUID、IDFA、IDFV
[Apple] iOS Security
[Github] FCUUID

关注作者

分享本文

目录