• 0

  • 0

浅谈iOS中的唯一标识符

2个月前

人从生下来开始就得上户口,从而获得一个身份证号,从此这个身份证号如影随形,跟这个人永远绑在一起,再也不分离。有些手续办起来,认号不认人,因为这个身份证号是唯一的,而人可能会变,比如整容等各种手段,所以判断是否是这个人,身份证号是一个相对不错的手段。

同样,一台设备,如果要有个准确的判断,以及要知道是不是同一台设备,一个唯一的设备标识符就显得尤为重要。iOS中唯一标识符主要经过下面几个阶段。

图片来源于网络

 

IMEI

IMEI(International Mobile Equipment Identity):国际移动设备身份码,在手机组装完成后赋予的一个全球唯一的号码。双卡双待手机有2个通信芯片,相当于2个手机装在1个手机外壳里面。而每个通信芯片都需要有IMEI标识,所以双卡双待手机有2个通信芯片,但是一般系统提供的api获取的是固定的那一个。

iOS2.0提供了获取IMEI的方法,但是iOS5.0之后不允许获取,否则上架时会审核不通过。

UDID

UDID(Unique Device Identifier):苹果 iOS 设备的唯一识别码。iOS6禁止获取。

现在如果要获取UDID/IMEI,可以通过Safari+mobileConfig来获取。

IDFA

IDFA(Identifier for Identifier),即广告标识符,多用于用户的广告追踪,是每台设备的唯一 ID,IDFA 存储在用户的系统上。Apple 是不允许开发者追踪用户设备的,但是为了监控广告效果,在 iOS 6 中提供这个折中方案。获取方法如下:

    NSString *idfa = nil;
    ASIdentifierManager * adManage = [ASIdentifierManager sharedManager];
    if (adManage.advertisingTrackingEnabled) {
        idfa = adManage.advertisingIdentifier.UUIDString;
    }
    return idfa;
复制代码

但 IDFA 也会发生变化,比如重置系统、还原广告标识符等。同时,用户也可以选择是否禁止广告追踪,操作路径:设置-隐私-广告-限制广告跟踪。限制广告跟踪之后返回的是nil。iOS14之前,默认是关闭的,而且整个系统是统一管理。iOS14之后,每个APP单独申请,默认是打开(限制)的。通过idfa归因逻辑大概如下:

 

MAC地址

Mac(Medium/Media Access Control):网络设备的物理地址,如果 IMEI 被认为是设备的唯一标识,那么 Mac 就是网络接口唯一标识。iOS7之后获得的Mac地址为一个固定值:02:00:00:00:00:00。获取方法如下:

#include <sys/sysctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>

+ (NSString *)getMacAddress {
    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");
        free(buf);
        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)];
    free(buf);
    
    return outstring;
}
复制代码

OpenUDID

openUIDI是由开源库[OpenUDID](https://github.com/ylechelle/OpenUDID)生成的识别码。它不依赖于Mac地址,可以起到以往UDID的作用。但是如果完全删除全部带有该开源库的APP,那么这个id会重新生成,而且和之前的值不同,相当于一台新设备。可惜因为iOS7对剪贴板进行了限制,该库也废掉了。

UUID

UUID(Universally Unique IDentifier):通用唯一识别码。获取方法如下:

[NSUUID UUID]
复制代码

每次获取的值都会变化,但会保持唯一性。

IDFV

IDFV(identifierForVendor):Vendor 标示符,也被称为厂商标识符。只要用户的设备中没有卸载当前 Vendor 的所有 APP,则不会发生变化。获取方法如下:

[[[UIDevice currentDevice] identifierForVendor] UUIDString]
复制代码

一般情况,vender由App Store提供的数据决定,如果安装的APP不是从App Store下载,比如通过enterprise包或者通过xcode安装的调试包,vender则由APP的bundle ID计算出来的。这个bundle ID符合reverse-DNS规则。在iOS6及之前,用bundle ID的前两位来生成vender ID,如果bundle ID是个单独的字符串,则由整个bundle ID来生成。在iOS7及以后,用bundle ID的非最后一位来生成vender ID,如果bundle ID是个单独的字符串,则由整个bundle ID来生成。具体见下表:

bundle ID iOS 6.x iOS 7.x
com.example.app1 com.example.app1 com.example.app1
com.example.app2 com.example.app2 com.example.app2
com.example.app.app1 com.example.app.app1 com.example.app.app1
com.example.app.app2 com.example.app.app2 com.example.app.app2
example example example

如上表,com.example.app1和com.example.app2有同样的vender ID。

数盟ID

APP方可应用数盟可信ID可作为识别设备唯一性的基准标识,不同于安卓的IMEI,MAC,序列号和iOS系统的IDFA等设备信息,它更不 易被篡改,不随Rom等变化改变,实时识别虚拟机环境等,完美兼容安卓10、iOS14平台。

SKAdNetwork

SKAdNetwork是让广告平台在不获取IDFA的前提下,对用户的点击和安装行为提供的一套追踪解决方案。由于Apple的介入,将直接横跨设备与App Store,并且不会把任何设备信息透露给广告主,并且更有利于防作弊。原理如下:

 

但是SKAdNetwork的应用场景比较单一,目前知道的主要是用来推广归因。

参考

免责声明:文章版权归原作者所有,其内容与观点不代表Unitimes立场,亦不构成任何投资意见或建议。

ios

0

相关文章推荐

未登录头像

暂无评论