iOS设备唯一标识的前世今生

设备唯一标识


      估计很多开发都有被要求过获取一下设备的唯一标识,获取设备的唯一标识经常使用在我们做统计或者是在保证一台设备登录亦或者是做IM的时候可能会考虑去使用它,这一次在自己的需求当中就有一个“账号绑定设备”的需求,这个需求不讨论它的实用性怎样,需求还是需要我们自己去完成。

      按照自己的理解针对这个设备的唯一标识,我还是建议少拿!当然说的是针对iOS的设备。下面就来总结一下这个唯一标识的发展过程。

一: UDID


      UDID是什么?

      你手机连接电脑的时候会弹出iTunes,通过它你就可以直观的看到一台设备的UDID,亦或者大家应该使用过“蒲公英”这个平台,要是你传到这个平台的ipa包要能安装在一台设备上的话就需要你在你自己的开发者证书当中添加到这台设备的UDID,这个过程在你直接使用Xcode连接设备的时候,Xcode也正确添加了开发者证书的前提下也是可以直接在你的开发者当中看到设备的UDID的,这个UDID是苹果给每一台设备配发的唯一标识,要是能直接使用它的话就可以直接解决上面我们的问题,可问题的关键是:

      在iOS 5 之后苹果是禁止获取该UDID了,iOS 5有点遥远了。

      比如下面是通过iTunes获取到的公司的测试机的设备信息:

      (有同事问我说为什么我iTunes的电话号码下面是序列号,不是UDID啊,你这是个假的iTunes吧!!哈哈....这怎么可能!你点击一下你的系列号试试!我把刀架在同事的脖子上问他是真的还是假的?)

二: IDFA


      IDFA又是什么玩意?

      IDFA俗称广告ID,估计在开发者里面提交用过应用的朋友都知道,在最后提交的时候苹果会问你有没有使用广告ID,不知道现在该有没有处于懵逼状态不懂苹果为什么要问这个的同行,看了我们这个就会清楚了为什么会这么问呢?这个广告ID就是IDFA。

      这个IDFA既然是苹果的玩意,那是不是我们就可以安心的用了,答案肯定是不行的,苹果在用户隐私这一方面还是挺重视的,你肯定是不能用的!在手机设置中你是可以关闭这个按钮的,如下所示:

       通过下面的一样代码你就能拿到这个IDFA:

    #import <AdSupport/AdSupport.h>

    NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
    NSLog(@"拿到的广告ID:%@",idfa);

三:MAC Address 


      MAC地址用来表示互联网上每一个站点的标识符,采用十六进制数表示,共六个字节(48位)。其中,前三个字节是由IEEE的注册管理机构 RA负责给不同厂家分配的代码(高位24位),也称为“编制上唯一的标识符” (Organizationally Unique Identifier),后三个字节(低位24位)由各厂家自行指派给生产的适配器接口,称为扩展标识符(唯一性)。

      MAC地址在网络上用来区分设备的唯一性,接入网络的设备都有一个MAC地址,他们肯定都是不同的,是唯一的。一部iPhone上可能有多个MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有一个WIFI的,因此只需获取WIFI的MAC地址就好了,也就是en0的地址。

      MAC地址就如同我们身份证上的身份证号码,具有全球唯一性。这样就可以非常好的标识设备唯一性,听着上面的解释是不是感觉很完美?

      but......

      在iOS 7.0之后你再去请求MAC地址,返回的永远都是同一个值!被禁了......

四:IDFV 也就是UUID


     UUID这个你获取起来是比较容易的,但你要是想使用这个作为手机的唯一标识也是不行的,为什么?

     我们用事实说明这个问题,下面的这些结论都是经过自己亲自测试的,在现有的版本中是没有问题的!!!

     获取UUID,通过下面的方法:

NSString *  strUUID = [UIDevice currentDevice].identifierForVendor.UUIDString

     下一步:你把手机的应用删除了再测试一下,我们的结论是:  要是只是单纯的这样获取UUID,删除了应用在重新安装是会发生变化的!

五:UUID + KeyChain


      说了上面的这么多,这个就是这篇文章的重点内容了,你获取到UUID之后把UUID存在系统钥匙串中,你看到这个方案肯定也有下面这些疑问:

      1、删除了应用这个标识会变吗?

      2、升级了系统这个标识会变吗?

      3、重置了系统之后呢?这个标识会变吗?

      4、既然是使用到了系统钥匙串的东西,那要是我把手机越狱了,会有问题吗?

      下面是我们这个方案的总的代码,先把代码给大家,完了我们再通过测试给上面的问题给出答案!给NSString添加一个UUID的类别:

//
//  NSString+UUID.h
//  Encapsulation
//
//  Created by Zhangxu on 2018/1/26.
//  获取UUID并存储到keyChain

#import <Foundation/Foundation.h>

@interface NSString (UUID)

+ (NSString *)getUUID;

@end


@interface KeyChainStore : NSObject

// 将UUID保存到钥匙串
+ (void)save:(NSString *)service data:(id)data;
// 读取保存到钥匙串的UUID
+ (id)load:(NSString *)service;
// 删除保存到钥匙串的UUID
+ (void)deleteKeyData:(NSString *)service;

@end

      上面是.h文件,下面就是 NSString+UUID.m 的文件:

//
//  NSString+UUID.m
//  Encapsulation
//  Created by Zhangxu on 2018/1/26.
//  获取UUID并存储到keyChain

#import "NSString+UUID.h"

@class KeyChainStore;

static NSString *  KEY_USERNAME_PASSWORD = @"com.Zhushi.ShuangLongChessAndCard";

@implementation NSString (UUID)

+(NSString *)getUUID
{
    NSString * strUUID = (NSString *)[KeyChainStore load:KEY_USERNAME_PASSWORD];
    //首次执行该方法时,uuid为空
    if ([strUUID isEqualToString:@""] || !strUUID)
    {
        //获取UUID
        strUUID = [UIDevice currentDevice].identifierForVendor.UUIDString;
        //将该uuid保存到keychain
        [KeyChainStore save:KEY_USERNAME_PASSWORD data:strUUID];
            
        //iPhone 8
        //11.2版本最初安装应用UUID FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE
        //11.2版本删除重装应用UUID FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE
        //升级系统11.2.5之后UUID  FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE
        
        //iPhone 6
        //10.3.3最初安装应用UUID   711CAC84-0540-4A44-80B4-26F87D2DD8B7
        //10.3.3删除重装应用UUID   711CAC84-0540-4A44-80B4-26F87D2DD8B7
        //升级11系统重装应用UUID    711CAC84-0540-4A44-80B4-26F87D2DD8B7
        //还原系统之后的应用UUID    1236FB53-CDCE-431E-999B-5C857C679B8A

    }
    return strUUID;
}

@end

#pragma mark -- KeyChainStore

@implementation KeyChainStore

+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service
{
    return [NSMutableDictionary dictionaryWithObjectsAndKeys:
            (id)kSecClassGenericPassword,(id)kSecClass,
            service, (id)kSecAttrService,
            service, (id)kSecAttrAccount,
            (id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,
            nil];
}

// 将UUID保存到钥匙串
+ (void)save:(NSString *)service data:(id)data
{
    //Get search dictionary
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    //Delete old item before add new item
    SecItemDelete((CFDictionaryRef)keychainQuery);
    //Add new object to search dictionary(Attention:the data format)
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData];
    //Add item to keychain with the search dictionary
    SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
}

// 读取保存到钥匙串的UUID
+ (id)load:(NSString *)service
{
    id ret = nil;
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    
    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
    [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
    CFDataRef keyData = NULL;
    if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr)
    {
        @try{
            ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
        } @catch (NSException *e) {
            NSLog(@"Unarchive of %@ failed: %@", service, e);
        } @finally {
        }
    }
    if (keyData)
        CFRelease(keyData);
    return ret;
}

// 删除保存到钥匙串的UUID
+ (void)deleteKeyData:(NSString *)service
{
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
    SecItemDelete((CFDictionaryRef)keychainQuery);
}

@end

      最后的结论:

      通过上面的代码你可以看到整个代码不是多么的复杂,我们关心的还是上面提出的几个疑问,我们一一测试:

      1、删除了应用之后这个标识会改变吗?

      结论:只要不是越狱的设备,删除应用之后是不会改变这个标识的!(越狱设备后面说!)

      2、升级了系统这个标识会变吗?

      下面是我把手机升级之后拿到的一组数据,测试机,就不给标识上码了...哈哈

      iPhone 8

      11.2版本最初安装应用UUID FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE

      11.2版本删除重装应用UUID FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE

      升级系统11.2.5之后UUID     FD6A5FE3-9EB4-422B-ADD3-17B313B9C8DE

      iPhone 6

      10.3.3最初安装应用UUID   711CAC84-0540-4A44-80B4-26F87D2DD8B7

      10.3.3删除重装应用UUID   711CAC84-0540-4A44-80B4-26F87D2DD8B7

      升级11系统重装应用UUID   711CAC84-0540-4A44-80B4-26F87D2DD8B7

      通过上面的这组数据,我们可以得到的结论是: 在现有版本情况下,升级系统是不会改变这个标识的!

      3、用于还原了设备会改变这个标识吗?我们再通过下面这组数据说明,拿我们的iPhone6当小白鼠,要是不知道怎样还原手机设备的看下面的: 设置 -> 通用 ->  还原

      看我们在小白鼠上拿到的数据:

      iPhone 6

      10.3.3最初安装应用UUID   711CAC84-0540-4A44-80B4-26F87D2DD8B7

      10.3.3删除重装应用UUID   711CAC84-0540-4A44-80B4-26F87D2DD8B7

      升级11系统重装应用UUID   711CAC84-0540-4A44-80B4-26F87D2DD8B7

      还原系统之后的应用UUID   1236FB53-CDCE-431E-999B-5C857C679B8A

      结论: 还原系统之后我们这个标识符真的改变了!!!!

      4、那要是设备越狱了呢?

      结论:在越狱设备上经过测试,是偶尔可以,偶尔不行!!!没错,就是这个结论!

      最后:

             通过上面的对比数据分析,结果我们也给大家了,通过上面的结论,你就知道了使用 UUID + KeyChain 的利弊,在目前中你想要做唯一标识 UUID + KeyChain 暂时应该是最科学的!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏技术博客

win7 64位系统及开发环境重装后的总结

   话说来这家公司之后就一直使用这个系统,现在感觉这系统跑的实在是有点慢了,运行,调试各种浪费时间呀,不过也用了将近20个月了,这也可以说是我用的最久的一个系...

13560
来自专栏飞雪无情的博客

Android 源码目录结构详解

这是Android2.1的源代码的目录结构,可以帮助我们研究Android的源代码。Android源代码的下载请参考官网

22420
来自专栏草根博客站长有话说

命令行界面 (CLI)、终端 (Terminal)、Shell、TTY,这些都是啥意思?

为什么突然想写这样一篇文章呢?其实是因为在最近计划发布的一篇关于 WSL (Windows Subsystem for Linux) 的博文中,我打算对终端模拟...

23260
来自专栏程序猿

tools for penetration test

渗透测试的几种工具介绍; Fiddler 代理服务应用 Fiddler 是一个免费的 Web 代理工具,具有浏览器和平台不可知性的特点。它有许多...

40670
来自专栏施炯的IoT开发专栏

Windows 10 IoT Serials 7 – 如何用树莓派制作家庭流媒体播放器

    Windows 10平台引入了AllJoyn开源软件框架,它提供了一组服务可以创建动态近端网络,让设备可以相互连接实现功能交互。目前,AllJoyn开源...

577100
来自专栏IT技术精选文摘

饿了么《分布式时序数据库 - LinDB》

77530
来自专栏BIT泽清

这十个步骤让你的 App 避规ios 4.3被拒问题,亲测顺利过审

ios开发子了解到,最近有大批开发者遇到了因为审核条款 4.3(后文统一简称 4.3)被 App Store 拒绝的情况。这种情况常见于大家上传CP,金融理财类...

1.2K70
来自专栏琯琯博客

awesome-linux-software-cn

Awesome-Linux-Software 是由 LewisVo 发起并维护的 Linux 软件资源列表。该列表收集了许多在 Linux 平台下非常棒的软件、...

1.4K140
来自专栏DannyHoo的专栏

iOS开发中时间戳和时间的相互转换

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

55110
来自专栏一“技”之长

iOS第三方网络诊断库——LDNetDiagnoService

        LDNetDiagnoService_IOS是一个开源的第三方网络诊断框架,它通过ping与traceroute原理来对指定域名进行网络诊断。并...

22320

扫码关注云+社区

领取腾讯云代金券