iOS开发之获取并存储设备唯一标识符

所谓唯一标识,顾名思义有两大特点:

  • 唯一性:就是从每一个设备上获取到的标识都具有唯一性
  • 标识性:通过两个设备上的标,能够充分代表两个不同的设备

iOS中能作为唯一标识符的有很多,如下:

  • UDID(Unique Device Identifier) iOS5之后被禁

  • UUID(Universally Unique Identifier)(苹果官方推荐

      (**注:如果用户完全重置系统((设置程序 -> 通用 -> 还原 -> 还原位置与隐私) ,这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序-> 通用 -> 关于本机 -> 广告 -> 还原广告标示符) ,那么广告标示符也会重新生成。**)
    
  • MAC Address iOS7被禁

  • OPEN UDID iOS7之后被禁

  • 广告标示符(IDFA-identifierForIdentifier) 可以使用,但因为本身性质,必须有广告服务,并且iTunes Connect上传要进行相关设置

      (**注:如果用户完全重置系统((设置程序 -> 通用 -> 还原 -> 还原位置与隐私) ,这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序-> 通用 -> 关于本机 -> 广告 -> 还原广告标示符) ,那么广告标示符也会重新生成。**)
    
  • Vendor标示符 (IDFV-identifierForVendor)

      (**注:如果用户卸载了同一个vendor对应的所有程序,然后在重新安装同一个vendor提供的程序,此时identifierForVendor会被重置**)
    
  • 推送token+bundle_id


获取唯一标识符方法:

方法一: 通过 CFUUID

  • 从iOS 2.0开始,CFUUID就已经出现了,它是CoreFoundation包的一部分,具有C语言的风格
    • 创建一个新的 UUID,参数一般传 nil
      CFUUIDRef CFUUIDCreate(CFAllocatorRef alloc);

    • 将 UUID 转换为 CFStringRef 类型
      CFStringRef CFUUIDCreateString(CFAllocatorRef alloc, CFUUIDRef uuid);

	- (NSString *)createUUID{
      			CFUUIDRef UUID = CFUUIDCreate(nil);
      			CFStringRef UUIDString = CFUUIDCreateString(nil, puuid);
      			NSString * result = (NSString *)CFBridgingRelease(CFStringCreateCopy( NULL, uuidString));
      			CFRelease(puuid);
      			CFRelease(uuidString);
      			return result;
			}

方法二: 通过 NSUUID

  • NSUUID 在 iOS6 中才出现,这根 CFUUID 几乎完全一样,只不过是 OC 接口
    • 创建 NSUUID
      +(instancetype)UUID;
    • 将转换为字符串
      @property (readonly, copy) NSString *UUIDString;

	+ (NSString *)createUUID{
      NSString *uuid = [NSUUID UUID].UUIDString;
      return uuid;
	}

方法三: 通过 Vindor标示符 (IDFV-identifierForVendor)

  • 这种叫法也是在 iOS 6 中新增的,不过获取这个 IDFV 的新方法被添加在已有的 UIDevice 类中。跟 advertisingIdentifier 一样,该方法返回的是一个 NSUUID 对象
    • Vindor标识符
      @property(nullable,nonatomic,readonly,strong) NSUUID*identifierForVendor

	+ (NSString *)createUUID{
      NSUUID * currentDeviceUUID  = [UIDevice currentDevice].identifierForVendor;
      return currentDeviceUUID.UUIDString;
	}

方法四: 通过广告标示符(IDFA-identifierForIdentifier)

  • 这是 iOS 6 中另外一个新的方法, advertisingIdentifier 是框架 AdSupport.framework 中的内容,因此在使用的时候需要引入框架,通过调用方法,可以看出 ASIdentifierManager 是一个单例, advertisingIdentifier 方法返回一个 NSUUID 对象

    • 单例创建
      +(ASIdentifierManager )sharedManager;
    • 调用方法,返回NSUUID
      @property (nonatomic,readonly) NSUUID advertisingIdentifier;

	+(NSString *)createUUID{
      NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
      return adId;
	}

由于每次调用上述方法,都会创建一个新的UUID,因此要想达到标识设备的作用,不得不需要做一些其他的操作,例如:

  • 通过NSUserDefaults存储 但是,当应用卸载重新安装的时候,NSUserDefaults会被重置,因此这种存储方式不是理想的办法
  • 通过钥匙串存储 这种方法可以避免因为应用卸载,而造成UUID不唯一的错误,下面主要介绍此方法

通过钥匙串存储方法

方案一: 基于 SSKeychain 的唯一识别码方案

  • 如上获取的UUID,基于Git上的一个第三方库SSKeychain,可以将UUID保存在keychain里面,每次调用先检查钥匙串里面有没有,有则使用,没有则写进去,保证其唯一性。

参考代码:


- (NSString *)getNewUniqueIdNum{

    NSString *uuidStr = [SSKeychain passwordForService:@"com.test.app1" account:@"user"];
    if (!uuidStr || [uuidStr isEqualToString:@""])
    {
        CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
        uuidStr = (__bridge NSString *)CFUUIDCreateString(kCFAllocatorDefault ,uuidRef);
        [SSKeychain setPassword:[NSString stringWithFormat:@"%@", uuidStr] forService:@"com.test.app1"account:@"user"];
    }
    return uuidStr;
}

不同于上面调用的字符串转换(__bridge NSString *),另一种写法:

- (NSString *)getNewUniqueIdNum{

    NSString *identifierNumber = [SSKeychain passwordForService:@"com.test.app1"account:@"user"];
    CFUUIDRef uuidRef = CFUUIDCreate(NULL);
    assert(uuidRef != NULL);
    CFStringRef uuidStrRef = CFUUIDCreateString(NULL, uuidRef);

    if (!identifierNumber){

        [SSKeychain setPassword: [NSString stringWithFormat:@"%@", uuidStrRef] forService:@"com.test.app1"account:@"user"];
        identifierNumber = [SSKeychain passwordForService:@"com.test.app1"account:@"user"];
    }
    return identifierNumber;
}

方案二: 基于 SAMKeyChains 方案

  • 不同于如上SSKeychain,基于一个第三方库SAMKeyChains。SAMKeyChains对苹果安全框架API进行了简单封装,支持对存储在钥匙串中密码、账户进行访问,包括读取、删除和设置。SAMKeyChains使用简单,通过实例代码便可掌握。

参考代码:


+ (NSString *)getDeviceId
{
    NSString * currentDeviceUUIDStr = [SAMKeychain passwordForService:@" "account:@"uuid"];
    if (currentDeviceUUIDStr == nil || [currentDeviceUUIDStr isEqualToString:@""])
    {
        NSUUID * currentDeviceUUID  =[[UIDevice currentDevice] identifierForVendor];
        currentDeviceUUIDStr = [currentDeviceUUID UUIDString];
        currentDeviceUUIDStr = [currentDeviceUUIDStr stringByReplacingOccurrencesOfString:@"-" withString:@""];
        currentDeviceUUIDStr = [currentDeviceUUIDStr lowercaseString];
        [SAMKeychain setPassword: currentDeviceUUIDStr forService:@" "account:@"uuid"];
    }
    return currentDeviceUUIDStr;
}

SAMKeyChains更多详细用法说明可以查看SAMKeyChains Documentation


推荐参考文献

其它参考文献

posted on 2017-08-09 17:54  小北在行走  阅读(313)  评论(0编辑  收藏  举报

导航