精华内容
下载资源
问答
  • ios 设备唯一标识

    2014-07-09 15:05:25
    英文原文:In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns the value 02:00:00:00:00:00. If you need to identify the device, use the identifierForVendor property ...

    英文原文:In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns the value 02:00:00:00:00:00. If you need to identify the device, use the identifierForVendor property of UIDevice instead. (Apps that need an identifier for their own advertising purposes should consider using the advertisingIdentifier property of ASIdentifierManager instead.)
    翻译:从iOS7及更高版本往后,如果你向ios设备请求获取mac地址,系统将返回一个固定值“02:00:00:00:00:00”,如果你需要识别设备的 唯一性,请使用UIDevice的identifierForVendor属性。(因广告目的而需要识别设备的应用,请考虑使用 ASIdentifierManager的advertisingIdentifier属性作为替代)


    这个MAC地址是指什么?有什么用?
           MAC(Medium/Media Access Control)地址,用来表示互联网上每一个站点的标识符,采用十六进制数表示,共六个字节(48位)。其中,前三个字节是由IEEE的注册管理机构 RA负责给不同厂家分配的代码(高位24位),也称为“编制上唯一的标识符” (Organizationally Unique Identifier),后三个字节(低位24位)由各厂家自行指派给生产的适配器接口,称为扩展标识符(唯一性)。
        MAC地址在网络上用来区分设备的唯一性,接入网络的设备都有一个MAC地址,他们肯定都是不同的,是唯一的。一部iPhone上可能有多个MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有一个WIFI的,因此只需获取WIFI的MAC地址就好了,也就是en0的地址。
          形象的说,MAC地址就如同我们身份证上的身份证号码,具有全球唯一性。这样就可以非常好的标识设备唯一性,类似与苹果设备的UDID号,通常的用途有:1)用于一些统计与分析目的,利用用户的操作习惯和数据更好的规划产品;2)作为用户ID来唯一识别用户,可以用游客身份使用app又能在服务器端保存相应的信息,省去用户名、密码等注册过程。


    那么,如何使用Mac地址生成设备的唯一标识呢?主要分三种:
    1、直接使用“MAC Address”
    2、使用“MD5(MAC Address)”
    3、使用“MD5(Mac Address+bundle_id)”获得“机器+应用”的唯一标识(bundle_id 是应用的唯一标识)


          iOS7之前,因为Mac地址是唯一的, 一般app开发者会采取第3种方式来识别安装对应app的设备。为什么会使用它?在iOS5之前,都是使用UDID的,后来被禁用。苹果推荐使用UUID 但是也有诸多问题,从而使用MAC地址。而MAC地址跟UDID一样,存在隐私问题,现在苹果新发布的iOS7上,如果请求Mac地址都会返回一个固定 值,那么Mac Address+bundle_id这个值大家的设备都变成一致的啦,跟UDID一样相当于被禁用。那么,要怎么标识设备唯一呢?


    在iOS系统中,获取设备唯一标识的方法有很多:
    一.UDID(Unique Device Identifier)


    二.UUID(Universally Unique Identifier)


    三.MAC Address


    四.OPEN UDID


    五.广告标示符(IDFA-identifierForIdentifier)


    六.Vindor标示符 (IDFV-identifierForVendor)


    七.推送token+bundle_id

     

    UDID的全称是Unique Device Identifier,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和数字组成(越狱的设备通过某些工具可以改变设备的UDID)。移动网络可利用UDID来识别移动设备,但是,从IOS5.0(2011年8月份)开始,苹果宣布将不再支持用uniqueIdentifier方法获取设备的UDID,iOS5以下是可以用的。在2013年3月21日苹果已经通知开发者:从2013年5月1日起,访问UIDIDs的程序将不再被审核通过,替代的方案是开发者应该使用“在iOS 6中介绍的Vendor或Advertising标示符”。所以UDID是绝对不能用啦。

     

    OPEN UDID,没有用到MAC地址,同时能保证同一台设备上的不同应用使用同一个OpenUDID,只要用户设备上有一个使用了OpenUDID的应用存在时,其他后续安装的应用如果获取OpenUDID,都将会获得第一个应用生成的那个。但是根据贡献者的代码和方法,和一些开发者的经验,如果把使用了OpenUDID方案的应用全部都删除,再重新获取OpenUDID,此时的OpenUDID就跟以前的不一样。可见,这种方法还是不保险。

     

     

     

    广告标示符,是iOS 6中另外一个新的方法,提供了一个方法advertisingIdentifier,通过调用该方法会返回一个NSUUID实例,最后可以获得一个UUID,由系统存储着的。不过即使这是由系统存储的,但是有几种情况下,会重新生成广告标示符。如果用户完全重置系统((设置程序 -> 通用 -> 还原 -> 还原位置与隐私) ,这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序-> 通用 -> 关于本机 -> 广告 -> 还原广告标示符) ,那么广告标示符也会重新生成。关于广告标示符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广 告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。

     

     

     

    Vindor标示符,也是在iOS 6中新增的,跟advertisingIdentifier一样,该方法返回的是一个 NSUUID对象,可以获得一个UUID。如果满足条件“相同的一个程序里面-相同的vindor-相同的设备”,那么获取到的这个属性值就不会变。如果是“相同的程序-相同的设备-不同的vindor,或者是相同的程序-不同的设备-无论是否相同的vindor”这样的情况,那么这个值是不会相同的。


    推送token+bundle_id的方法:
    1、应用中增加推送用来获取token
    2、获取应用bundle_id
    3、根据token+bundle_id进行散列运算


    apple push token保证设备唯一,但必须有网络情况下才能工作,该方法不依赖于设备本身,但依赖于apple push,而苹果push有时候会抽风的。


    UUID是Universally Unique Identifier的缩写,中文意思是通用唯一识别码。它是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定。这样,每个人都可以建立不与其它人冲突的 UUID。在此情况下,就不需考虑数据库建立时的名称重复问题。苹果公司建议使用UUID为应用生成唯一标识字符串。


     

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    iOS中获取UUID的代码如下: 
    -(NSString*) uuid {  
        CFUUIDRef puuid = CFUUIDCreate( nil );  
        CFStringRef uuidString = CFUUIDCreateString( nil, puuid );  
        NSString * result = (NSString *)CFStringCreateCopy( NULL, uuidString);  
        CFRelease(puuid);  
        CFRelease(uuidString);  
        return [result autorelease];  
    iOS中获取网卡mac的代码如下:
    #include <sys/socket.h> // Per msqr 
    #include <sys/sysctl.h> 
    #include <net/if.h> 
    #include <net/if_dl.h> 
       
    #pragma mark MAC addy 
    // Return the local MAC addy 
    // Courtesy of FreeBSD hackers email list 
    // Accidentally munged during previous update. Fixed thanks to mlamb. 
    - (NSString *) macaddress
    {
        int                    mib[6];
        size_t                len;
        char                *buf;
        unsigned char        *ptr;
        struct if_msghdr    *ifm;
        struct sockaddr_dl    *sdl;
          
        mib[0] = CTL_NET;
        mib[1] = AF_ROUTE;
        mib[2] = 0;
        mib[3] = AF_LINK;
        mib[4] = NET_RT_IFLIST;
          
        if ((mib[5] = if_nametoindex("en0")) == 0) {
            printf("Error: if_nametoindex error/n");
            return NULL;
        }
          
        if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
            printf("Error: sysctl, take 1/n");
            return NULL;
        }
          
        if ((buf = malloc(len)) == NULL) {
            printf("Could not allocate memory. error!/n");
            return NULL;
        }
          
        if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
            printf("Error: sysctl, take 2");
            return NULL;
        }
          
        ifm = (struct if_msghdr *)buf;
        sdl = (struct sockaddr_dl *)(ifm + 1);
        ptr = (unsigned char *)LLADDR(sdl);
        // NSString *outstring = [NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)]; 
        NSString *outstring = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
        free(buf);
        return [outstring uppercaseString];
    }
     
    iOS中获取UUID的代码如下:
    -(NSString*) uuid {
        CFUUIDRef puuid = CFUUIDCreate( nil );
        CFStringRef uuidString = CFUUIDCreateString( nil, puuid );
        NSString * result = (NSString *)CFStringCreateCopy( NULL, uuidString);
        CFRelease(puuid);
        CFRelease(uuidString);
        return [result autorelease];
    }
    iOS中获取网卡mac的代码如下:
    #include <sys/socket.h> // Per msqr
    #include <sys/sysctl.h>
    #include <net/if.h>
    #include <net/if_dl.h>
      
    #pragma mark MAC addy
    // Return the local MAC addy
    // Courtesy of FreeBSD hackers email list
    // Accidentally munged during previous update. Fixed thanks to mlamb.
    - (NSString *) macaddress
    {
        int                    mib[6];
        size_t                len;
        char                *buf;
        unsigned char        *ptr;
        struct if_msghdr    *ifm;
        struct sockaddr_dl    *sdl;
        
        mib[0] = CTL_NET;
        mib[1] = AF_ROUTE;
        mib[2] = 0;
        mib[3] = AF_LINK;
        mib[4] = NET_RT_IFLIST;
        
        if ((mib[5] = if_nametoindex("en0")) == 0) {
            printf("Error: if_nametoindex error/n");
            return NULL;
        }
        
        if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
            printf("Error: sysctl, take 1/n");
            return NULL;
        }
        
        if ((buf = malloc(len)) == NULL) {
            printf("Could not allocate memory. error!/n");
            return NULL;
        }
        
        if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
            printf("Error: sysctl, take 2");
            return NULL;
        }
        
        ifm = (struct if_msghdr *)buf;
        sdl = (struct sockaddr_dl *)(ifm + 1);
        ptr = (unsigned char *)LLADDR(sdl);
        // NSString *outstring = [NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
        NSString *outstring = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
        free(buf);
        return [outstring uppercaseString];
    }

    开发者可以在应用第一次启动时调用一 次,然后将该串存储起来,以便以后替代UDID来使用。但是,如果用户删除该应用再次安装时,又会生成新的字符串,所以不能保证唯一识别该设备。这就需要各路高手想出各种解决方案。所以,之前很多应用就采用MAC Address。但是现在如果用户升级到iOS7(及其以后的苹果系统)后,他们机子的MAC Address就是一样的,没办法做区分,只能弃用此方法,重新使用UUID来标识。如果使用UUID,就要考虑应用被删除后再重新安装时的处理。

     

    一个解决的办法是:UUID一般只生成一次,保存在iOS系统里面,如果应用删除了,重装应用之后它的UUID还是一样的,除非系统重置 。但是不能保证在以后的系统升级后还能用(如果系统保存了该信息就能用).

    由于IOS系统存储的数据都是在sandBox里面,一旦删除App,sandBox也不复存在。好在有一个例外,那就是keychain(钥匙串)。


    通常情况下,IOS系统用NSUserDefaults存储数据信息,但是对于一些私密信息,比如密码、证书等等,就需要使用更为安全的keychain了。


    keychain里保存的信息不会因App被删除而丢失。所以,可以利用这个keychain这个特点来保存设备唯一标识。


    那么,如何在应用里使用使用keyChain呢,我们需要导入Security.framework ,keychain的操作接口声明在头文件SecItem.h里。


    直接使用SecItem.h里方法操作keychain,需要写的代码较为复杂,我们可以使用已经封装好了的工具类KeychainItemWrapper来对keychain进行操作。


    KeychainItemWrapper是apple官方例子“GenericKeychain”里一个访问keychain常用操作的封装类,在官网上下载了GenericKeychain项目后,


    只需要把“KeychainItemWrapper.h”和“KeychainItemWrapper.m”拷贝到我们项目,并导入Security.framework 。KeychainItemWrapper的用法:


    /** 初始化一个保存用户帐号的KeychainItemWrapper */
    KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"Account Number"
                                                                       accessGroup:@"YOUR_APP_ID_HERE.com.yourcompany.AppIdentifier"]; 
     
    //保存数据
    [wrapper setObject:@"<帐号>" forKey:(id)kSecAttrAccount];   
     
    [wrapper setObject:@"<帐号密码>" forKey:(id)kSecValueData];   
     
    //从keychain里取出帐号密码
    NSString *password = [wrapper objectForKey:(id)kSecValueData];     
     
    //清空设置
    [wrapper resetKeychainItem];
    其中方法“- (void)setObject:(id)inObject forKey:(id)key;”里参数“forKey”的值应该是Security.framework 里头文件“SecItem.h”里定义好的key,用其他字符串做key程序会出错!

    展开全文
  • iOS设备唯一标识

    2015-05-07 09:55:41
    哪位老师研究过友盟SDK中iOS设备唯一标识算法? 指点下小弟?
  • 获取iOS设备唯一标识

    2017-07-06 13:00:00
    获取iOS设备唯一标识 获取iOS设备唯一标识大纲 思维导图 详情 思维导图详情 UDID 在之前的版本是可以被使用的,iOS5及以后,被苹果禁止使用了(弃用了)。虽然,这个UDID用得很广泛,但是...

    获取iOS设备唯一标识

    获取iOS设备唯一标识
    大纲
    • 思维导图

    • 详情

    思维导图
    详情

    UDID

    在之前的版本是可以被使用的,iOS5及以后,被苹果禁止使用了(弃用了)。虽然,这个UDID用得很广泛,但是,不得不说的是,它在慢慢的远离开发者,不能在考虑使用UDID了。至于这个标示符是转为私有方法,或者完全从以后的iOS版本中移除,还有待观察。不过,这个UDID在部署企业级签名程序时,非常方便。

    获取UDID的方法如下: NSString *udid = [[UIDevice currentDevice] uniqueIdentifier];

    示例:bb4d786633053a0b9c0da20d54ea7e38e8776da4

    OpenUDID(github上一个开源的项目)

    在iOS 5发布时,UDID被弃用了,这引起了广大开发者需要寻找一个可以替代UDID,并且不受苹果控制的方案。由此OpenUDID成为了当时使用最广泛的开源UDID替代方案。OpenUDID在工程中实现起来非常简单,并且还支持一系列的广告提供商。

    获取UDID的方法如下: NSString *openUDID = [OpenUDID value];

    OpenUDID原理是利用iOS系统中的UIPasteboard剪贴板类,它用 app-special pastboards 来存储一160位的随机字符串,存取的方式类似字典的key-value。 app-special pastboards 可持久存储字符串,即使开关机、卸载应用,并能在app之间共享。Openudid的第一次访问的时候用key去检查剪贴板内是否存在对应的value(随机数),如果不存在就生成一个并存储在Pasteboard中,第二次访问的时候就可以直接取到而不去生成新的随机数。 但是iOS7之后,苹果封堵了剪贴板通信的漏洞,iOS之前是所有的应用都可以共享同一个剪贴板存储内容,现在只有在同一CFBundleIdentifier标识下的App才能共享内容,如com.koudai.a和com.koudai.b,它们的com.mycompany部分是一样的,就能共享(请用真机测试,模拟器会有偏差)。

    UUID

    目前大部分应用存的是UUID,它是苹果再iOS6后提供的一个获取大随机数的方法。UUID, 全球独立标识(Globally Unique Identifier),据wiki说UUID随机数算法得到的数重复概率为170亿分之一,170亿分之一什么概念?可以告诉你买一注双色球的中奖概率是1700万分之一。

    以下是几种取到UUID的方法,它们各有区别:

    CFUUID

    从iOS2.0开始,CFUUID就已经出现了。它是CoreFoundatio包的一部分,因此API属于C语言风格。CFUUIDCreate 方法用来创建CFUUIDRef,并且可以获得一个相应的NSString。获得的这个CFUUID值系统并没有存储。每次调用CFUUIDCreate,系统都会返回一个新的唯一标示符。如果你希望存储这个标示符,那么需要自己将其存储到NSUserDefaults, Keychain, Pasteboard或其它地方。

    获取CFUUID方法如下: CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);NSString *cfuuidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));

    示例:68753A44-4D6F-1226-9C60-0050E4C00067

    NSUUID

    NSUUID在iOS 6中才出现,这跟CFUUID几乎完全一样,只不过它是Objective-C接口。跟CFUUID一样,这个值系统也不会存储,每次调用的时候都会获得一个新的唯一标示符。如果要存储的话,你需要自己存储。

    获取NSUUID方法如下:NSString *uuid = [[NSUUID UUID] UUIDString];

    示例:68753A44-4D6F-1226-9C60-0050E4C00067

    IDFA-identifierForIdentifier

    这是iOS 6中另外一个新的方法,advertisingIdentifier是新框架AdSupport.framework的一部分。ASIdentifierManager单例提供了一个方法advertisingIdentifier,通过调用该方法会返回一个上面提到的NSUUID实例。

    跟CFUUID和NSUUID不一样,广告标示符是由系统存储着的。不过即使这是由系统存储的,但是有几种情况下,会重新生成广告标示符。如果用户完全重置系统((设置程序 -> 通用 -> 还原 -> 还原位置与隐私) ,这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序-> 通用 -> 关于本机 -> 广告 -> 还原广告标示符) ,那么广告标示符也会重新生成。关于广告标示符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。之所以会这样,我猜测是由于ASIdentifierManager是一个单例。

    针对广告标示符用户有一个可控的开关“限制广告跟踪”。Nick Arnott的文章中已经指出了。将这个开关打开,实际上什么也没有做,不过这是希望限制你访问广告标示符。这个开关是一个简单的boolean标志,当将广告标示符发到任意的服务器端时,你最好判断一下这个值,然后再做决定。

    注意:Appstore禁止不使用广告而采集IDFA的app上架。请参考

    获取IDFA方法如下:NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

    示例:E2DFA89-496A-47FD-9941-DF1FC4E6484A

    IDFV-identifierForVendor

    这种叫法也是在iOS 6中新增的,不过获取这个IDFV的新方法被添加在已有的UIDevice类中。跟advertisingIdentifier一样,该方法返回的是一个NSUUID对象。

    苹果官方的文档中对identifierForVendor有如下这样的一段描述 : The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps on the same device that come from different vendors, and for apps on different devices regardless of vendor.意思是根据vendor的值,如果vendor相同,则返回同一字符串;如果vendor不同,则返回不同的字符串。

    vendor解释:英文解释为卖家,小贩。根据xcode文档解释,正常情况下,会根据App Store提供的数据进行判断。但是如果app不是通过app store进行安装的(如企业应用或开发调试阶段),那么会根据bundle ID判断。

    获取IDFA方法如下:NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];

    示例:E2DFA89-496A-47FD-9941-DF1FC4E6484A

    注:天生的普通人

    转载于:https://www.cnblogs.com/fdyjm/p/7125710.html

    展开全文
  • iOS-通过UUID来获取iOS设备唯一标识

    千次阅读 2019-01-03 16:35:20
    在之前的版本是可以使用UDID获取iOS设备唯一标识, NSString *udidString = [[UIDevice currentDevice] uniqueIdentifier]; 但是iOS5及以后,被苹果禁止使用了(弃用了) 而直接获取的UUID系统不会存储,每次...

    在之前的版本是可以使用UDID获取iOS设备唯一标识,

    NSString *udidString = [[UIDevice currentDevice] uniqueIdentifier];

    但是iOS5及以后,被苹果禁止使用了(弃用了)

    而直接获取的UUID系统不会存储,每次调用的时候都会获得一个新的UUID标示符
    一般获取UUID的方法如下


    我们可以通过持久存储这个标识符,来保证即使重新加载,删除后重装应用都能够唯一标识,以下的方式通过获取到UUID后存入系统中的keychain中,来保证以后每次可以得到相同的唯一标志。
    代码如下:

    #import "UUIDTool.h"

    NSString * const kUUIDKey = @"com.myApp.uuid";

    @implementation UUIDTool

    #pragma mark - 获取到UUID后存入系统中的keychain中

    + (NSString *)getUUIDInKeychain {
        // 1.直接从keychain中获取UUID
        NSString *getUDIDInKeychain = (NSString *)[UUIDTool load:kUUIDKey];
        NSLog(@"从keychain中获取UUID%@", getUDIDInKeychain);
        
        // 2.如果获取不到,需要生成UUID并存入系统中的keychain
        if (!getUDIDInKeychain || [getUDIDInKeychain isEqualToString:@""] || [getUDIDInKeychain isKindOfClass:[NSNull class]]) {
            // 2.1 生成UUID
            CFUUIDRef puuid = CFUUIDCreate(nil);
            CFStringRef uuidString = CFUUIDCreateString(nil, puuid);
            NSString *result = (NSString *)CFBridgingRelease(CFStringCreateCopy(NULL, uuidString));
            CFRelease(puuid);
            CFRelease(uuidString);
            NSLog(@"生成UUID:%@",result);
            // 2.2 将生成的UUID保存到keychain中
            [UUIDTool save:kUUIDKey data:result];
            // 2.3 从keychain中获取UUID
            getUDIDInKeychain = (NSString *)[UUIDTool load:kUUIDKey];
        }
        
        return getUDIDInKeychain;
    }


    #pragma mark - 删除存储在keychain中的UUID

    + (void)deleteKeyChain {
        [self delete:kUUIDKey];
    }


    #pragma mark - 私有方法

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

    // 从keychain中获取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 *exception) {
                NSLog(@"Unarchive of %@ failed: %@", service, exception);
            }
            @finally {
                NSLog(@"finally");
            }
        }
        
        if (keyData) {
            CFRelease(keyData);
        }
        NSLog(@"ret = %@", ret);
        return ret;
    }

    + (void)delete:(NSString *)service {
        NSMutableDictionary *keychainQuery = [self getKeyChainQuery:service];
        SecItemDelete((CFDictionaryRef)keychainQuery);
    }

    // 将生成的UUID保存到keychain中
    + (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);
    }

    另外附上GitHub上的Demo链接:https://github.com/rambocai/ZYUUID-Emon.git

    作者:雪落倾城
    链接:https://www.jianshu.com/p/0dce89cdf9f6
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

     

    展开全文
  • ios设备唯一标识获取策略 2013-08-20 13:22:32 我来说两句 作者:MyGameZone 收藏 我要投稿 英文原文:In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns ...
    ios设备唯一标识获取策略


    英文原文:In iOS 7 and later, if you ask for the MAC address of an iOS device, the system returns the value 02:00:00:00:00:00. If you need to identify the device, use the identifierForVendor property of UIDevice instead. (Apps that need an identifier for their own advertising purposes should consider using the advertisingIdentifier property of ASIdentifierManager instead.)
    翻译:从iOS7及更高版本往后,如果你向ios设备请求获取mac地址,系统将返回一个固定值“02:00:00:00:00:00”,如果你需要识别设备的 唯一性,请使用UIDevice的identifierForVendor属性。(因广告目的而需要识别设备的应用,请考虑使用 ASIdentifierManager的advertisingIdentifier属性作为替代)


    这个MAC地址是指什么?有什么用?
           MAC(Medium/Media Access Control)地址,用来表示互联网上每一个站点的标识符,采用十六进制数表示,共六个字节(48位)。其中,前三个字节是由IEEE的注册管理机构 RA负责给不同厂家分配的代码(高位24位),也称为“编制上唯一的标识符” (Organizationally Unique Identifier),后三个字节(低位24位)由各厂家自行指派给生产的适配器接口,称为扩展标识符(唯一性)。
        MAC地址在网络上用来区分设备的唯一性,接入网络的设备都有一个MAC地址,他们肯定都是不同的,是唯一的。一部iPhone上可能有多个MAC地址,包括WIFI的、SIM的等,但是iTouch和iPad上就有一个WIFI的,因此只需获取WIFI的MAC地址就好了,也就是en0的地址。
          形象的说,MAC地址就如同我们身份证上的身份证号码,具有全球唯一性。这样就可以非常好的标识设备唯一性,类似与苹果设备的UDID号,通常的用途有:1)用于一些统计与分析目的,利用用户的操作习惯和数据更好的规划产品;2)作为用户ID来唯一识别用户,可以用游客身份使用app又能在服务器端保存相应的信息,省去用户名、密码等注册过程。


    那么,如何使用Mac地址生成设备的唯一标识呢?主要分三种:
    1、直接使用“MAC Address”
    2、使用“MD5(MAC Address)”
    3、使用“MD5(Mac Address+bundle_id)”获得“机器+应用”的唯一标识(bundle_id 是应用的唯一标识)


          iOS7之前,因为Mac地址是唯一的, 一般app开发者会采取第3种方式来识别安装对应app的设备。为什么会使用它?在iOS5之前,都是使用UDID的,后来被禁用。苹果推荐使用UUID 但是也有诸多问题,从而使用MAC地址。而MAC地址跟UDID一样,存在隐私问题,现在苹果新发布的iOS7上,如果请求Mac地址都会返回一个固定 值,那么Mac Address+bundle_id这个值大家的设备都变成一致的啦,跟UDID一样相当于被禁用。那么,要怎么标识设备唯一呢?


    在iOS系统中,获取设备唯一标识的方法有很多:
    一.UDID(Unique Device Identifier)


    二.UUID(Universally Unique Identifier)


    三.MAC Address


    四.OPEN UDID


    五.广告标示符(IDFA-identifierForIdentifier)


    六.Vindor标示符 (IDFV-identifierForVendor)


    七.推送token+bundle_id

     

    UDID的全称是Unique Device Identifier,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和数字组成(越狱的设备通过某些工具可以改变设备的UDID)。移动网络可利用UDID来识别移动设备,但是,从IOS5.0(2011年8月份)开始,苹果宣布将不再支持用uniqueIdentifier方法获取设备的UDID,iOS5以下是可以用的。在2013年3月21日苹果已经通知开发者:从2013年5月1日起,访问UIDIDs的程序将不再被审核通过,替代的方案是开发者应该使用“在iOS 6中介绍的Vendor或Advertising标示符”。所以UDID是绝对不能用啦。

     

    OPEN UDID,没有用到MAC地址,同时能保证同一台设备上的不同应用使用同一个OpenUDID,只要用户设备上有一个使用了OpenUDID的应用存在时,其他后续安装的应用如果获取OpenUDID,都将会获得第一个应用生成的那个。但是根据贡献者的代码和方法,和一些开发者的经验,如果把使用了OpenUDID方案的应用全部都删除,再重新获取OpenUDID,此时的OpenUDID就跟以前的不一样。可见,这种方法还是不保险。

     

     

     

    广告标示符,是iOS 6中另外一个新的方法,提供了一个方法advertisingIdentifier,通过调用该方法会返回一个NSUUID实例,最后可以获得一个UUID,由系统存储着的。不过即使这是由系统存储的,但是有几种情况下,会重新生成广告标示符。如果用户完全重置系统((设置程序 -> 通用 -> 还原 -> 还原位置与隐私) ,这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序-> 通用 -> 关于本机 -> 广告 -> 还原广告标示符) ,那么广告标示符也会重新生成。关于广告标示符的还原,有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广 告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。

     

     

     

    Vindor标示符,也是在iOS 6中新增的,跟advertisingIdentifier一样,该方法返回的是一个 NSUUID对象,可以获得一个UUID。如果满足条件“相同的一个程序里面-相同的vindor-相同的设备”,那么获取到的这个属性值就不会变。如果是“相同的程序-相同的设备-不同的vindor,或者是相同的程序-不同的设备-无论是否相同的vindor”这样的情况,那么这个值是不会相同的。


    推送token+bundle_id的方法:
    1、应用中增加推送用来获取token
    2、获取应用bundle_id
    3、根据token+bundle_id进行散列运算


    apple push token保证设备唯一,但必须有网络情况下才能工作,该方法不依赖于设备本身,但依赖于apple push,而苹果push有时候会抽风的。


    UUID是Universally Unique Identifier的缩写,中文意思是通用唯一识别码。它是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定。这样,每个人都可以建立不与其它人冲突的 UUID。在此情况下,就不需考虑数据库建立时的名称重复问题。苹果公司建议使用UUID为应用生成唯一标识字符串。


     

    ?
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    iOS中获取UUID的代码如下: 
    -(NSString*) uuid {  
        CFUUIDRef puuid = CFUUIDCreate( nil );  
        CFStringRef uuidString = CFUUIDCreateString( nil, puuid );  
        NSString * result = (NSString *)CFStringCreateCopy( NULL, uuidString);  
        CFRelease(puuid);  
        CFRelease(uuidString);  
        return [result autorelease];  
    iOS中获取网卡mac的代码如下:
    #include <sys/socket.h> // Per msqr 
    #include <sys/sysctl.h> 
    #include <net/if.h> 
    #include <net/if_dl.h> 
       
    #pragma mark MAC addy 
    // Return the local MAC addy 
    // Courtesy of FreeBSD hackers email list 
    // Accidentally munged during previous update. Fixed thanks to mlamb. 
    - (NSString *) macaddress
    {
        int                    mib[6];
        size_t                len;
        char                *buf;
        unsigned char        *ptr;
        struct if_msghdr    *ifm;
        struct sockaddr_dl    *sdl;
          
        mib[0] = CTL_NET;
        mib[1] = AF_ROUTE;
        mib[2] = 0;
        mib[3] = AF_LINK;
        mib[4] = NET_RT_IFLIST;
          
        if ((mib[5] = if_nametoindex("en0")) == 0) {
            printf("Error: if_nametoindex error/n");
            return NULL;
        }
          
        if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
            printf("Error: sysctl, take 1/n");
            return NULL;
        }
          
        if ((buf = malloc(len)) == NULL) {
            printf("Could not allocate memory. error!/n");
            return NULL;
        }
          
        if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
            printf("Error: sysctl, take 2");
            return NULL;
        }
          
        ifm = (struct if_msghdr *)buf;
        sdl = (struct sockaddr_dl *)(ifm + 1);
        ptr = (unsigned char *)LLADDR(sdl);
        // NSString *outstring = [NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)]; 
        NSString *outstring = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
        free(buf);
        return [outstring uppercaseString];
    }
     
    iOS中获取UUID的代码如下:
    -(NSString*) uuid {
        CFUUIDRef puuid = CFUUIDCreate( nil );
        CFStringRef uuidString = CFUUIDCreateString( nil, puuid );
        NSString * result = (NSString *)CFStringCreateCopy( NULL, uuidString);
        CFRelease(puuid);
        CFRelease(uuidString);
        return [result autorelease];
    }
    iOS中获取网卡mac的代码如下:
    #include <sys/socket.h> // Per msqr
    #include <sys/sysctl.h>
    #include <net/if.h>
    #include <net/if_dl.h>
      
    #pragma mark MAC addy
    // Return the local MAC addy
    // Courtesy of FreeBSD hackers email list
    // Accidentally munged during previous update. Fixed thanks to mlamb.
    - (NSString *) macaddress
    {
        int                    mib[6];
        size_t                len;
        char                *buf;
        unsigned char        *ptr;
        struct if_msghdr    *ifm;
        struct sockaddr_dl    *sdl;
        
        mib[0] = CTL_NET;
        mib[1] = AF_ROUTE;
        mib[2] = 0;
        mib[3] = AF_LINK;
        mib[4] = NET_RT_IFLIST;
        
        if ((mib[5] = if_nametoindex("en0")) == 0) {
            printf("Error: if_nametoindex error/n");
            return NULL;
        }
        
        if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
            printf("Error: sysctl, take 1/n");
            return NULL;
        }
        
        if ((buf = malloc(len)) == NULL) {
            printf("Could not allocate memory. error!/n");
            return NULL;
        }
        
        if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
            printf("Error: sysctl, take 2");
            return NULL;
        }
        
        ifm = (struct if_msghdr *)buf;
        sdl = (struct sockaddr_dl *)(ifm + 1);
        ptr = (unsigned char *)LLADDR(sdl);
        // NSString *outstring = [NSString stringWithFormat:@"%02x:%02x:%02x:%02x:%02x:%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
        NSString *outstring = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
        free(buf);
        return [outstring uppercaseString];
    }

    开发者可以在应用第一次启动时调用一 次,然后将该串存储起来,以便以后替代UDID来使用。但是,如果用户删除该应用再次安装时,又会生成新的字符串,所以不能保证唯一识别该设备。这就需要各路高手想出各种解决方案。所以,之前很多应用就采用MAC Address。但是现在如果用户升级到iOS7(及其以后的苹果系统)后,他们机子的MAC Address就是一样的,没办法做区分,只能弃用此方法,重新使用UUID来标识。如果使用UUID,就要考虑应用被删除后再重新安装时的处理。

     

    一个解决的办法是:UUID一般只生成一次,保存在iOS系统里面,如果应用删除了,重装应用之后它的UUID还是一样的,除非系统重置 。但是不能保证在以后的系统升级后还能用(如果系统保存了该信息就能用).

    由于IOS系统存储的数据都是在sandBox里面,一旦删除App,sandBox也不复存在。好在有一个例外,那就是keychain(钥匙串)。


    通常情况下,IOS系统用NSUserDefaults存储数据信息,但是对于一些私密信息,比如密码、证书等等,就需要使用更为安全的keychain了。


    keychain里保存的信息不会因App被删除而丢失。所以,可以利用这个keychain这个特点来保存设备唯一标识。


    那么,如何在应用里使用使用keyChain呢,我们需要导入Security.framework ,keychain的操作接口声明在头文件SecItem.h里。


    直接使用SecItem.h里方法操作keychain,需要写的代码较为复杂,我们可以使用已经封装好了的工具类KeychainItemWrapper来对keychain进行操作。


    KeychainItemWrapper是apple官方例子“GenericKeychain”里一个访问keychain常用操作的封装类,在官网上下载了GenericKeychain项目后,


    只需要把“KeychainItemWrapper.h”和“KeychainItemWrapper.m”拷贝到我们项目,并导入Security.framework 。KeychainItemWrapper的用法:


    /** 初始化一个保存用户帐号的KeychainItemWrapper */
    KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"Account Number"
                                                                       accessGroup:@"YOUR_APP_ID_HERE.com.yourcompany.AppIdentifier"]; 
     
    //保存数据
    [wrapper setObject:@"<帐号>" forKey:(id)kSecAttrAccount];   
     
    [wrapper setObject:@"<帐号密码>" forKey:(id)kSecValueData];   
     
    //从keychain里取出帐号密码
    NSString *password = [wrapper objectForKey:(id)kSecValueData];     
     
    //清空设置
    [wrapper resetKeychainItem];
    其中方法“- (void)setObject:(id)inObject forKey:(id)key;”里参数“forKey”的值应该是Security.framework 里头文件“SecItem.h”里定义好的key,用其他字符串做key程序会出错!

    展开全文
  • iOS设备唯一标识探讨 为了统计和检测应用的使用数据,几乎每家公司都有获取唯一标识的业务需求,在iOS5以前获取唯一标识,可以获取到系统提供的方法UDID(Unique Device Identifier),后来被出于用户隐私的考虑被...
  • iOS设备唯一标识探讨

    千次阅读 2016-05-16 15:29:55
    首先iOS中获取设备唯一标示符的方法一直随版本的更新而变化。iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符的方法uniqueIdentifier,通过该方法我们可以获取设备的序列号,这个也是目前为止唯一可以确认唯一的...
  • 设备唯一标识 估计很多开发都有被要求过获取一下设备的唯一标识,获取设备的唯一标识经常使用在我们做统计或者是在保证一台设备登录亦或者是做IM的时候可能会考虑去使用它,这一次在自己的需求当中就有一个...
  • 获取UUID 写了两个文件CMKeyChain CMUUIDManager 用了好几年 表示挺好用的 分享下 该方法App卸载 UUID不变 可上架AppStore 本人已上线N个该方法App 相当于安卓的IMEI 用法很简单 写一个类方法就行了 导入头文件#...
  • 获取IOS设备唯一标识

    2016-10-23 14:46:00
    http://www.cnblogs.com/tekkaman/p/4003895.html 转载于:https://www.cnblogs.com/ArcherHuang/p/5990029.html
  • 通过UDID、Mac地址、OpenUDID获取设备标识已经被苹果禁用 但是苹果提供了idfa和idfv两种方法获取设备标识 1、 NSString *idfv = [[UIDevice currentDevice].identifierForVendor UUIDString]; 2、 ...
  • 在iOS系统中,获取设备唯一标识的方法有很多:一.UDID(Unique Device Identifier) UDID的全称是Unique Device Identifier,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和数字组成(越狱的设备通过某些工具...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 528
精华内容 211
关键字:

ios设备唯一标识