zoukankan      html  css  js  c++  java
  • 获取UUID并保存到钥匙串

    前言:

    1 .为了统计和检测应用的使用数据,几乎每家公司都有获取唯一标识的业务需求,在iOS5以前获取唯一标识,可以获取到系统提供的方法UDID(Unique Device Identifier),后来被出于用户隐私的考虑被Apple官方禁止掉了。于是,大家开始在iOS6中使用 MAC 地址(Medium/Media Access Control) ,后来又被Apple官方在iOS7中禁止掉了。苹果及其国外的IT公司都会比较注重用户隐私,所以今后一但有比较靠谱的获取唯一标示的方法放出,苹果肯定会封堵。

    2.**  ** 在非越狱的手机上获取某个硬件信息生成唯一标识,第一只能找到苹果的漏洞,第二就是调用一些私有接口,显然这两条路都比较艰难,并不可持续发展,所以网上大部分的唯一标识都是从操作系统层面获取的,在重置手机系统的时候都会被清除,在系统升级、卸载重装、备份恢复都可以保留,现在本人尚未发现可以使用严格意义上的唯一标识。接下来我想跟大家探讨的是如何通过“合法”的手段来尽量拿到不会轻易发生变化的“唯一标识”。

    3.**  **在2013年3月21日苹果已经通知开发者,从2013年5月1日起,访问UIDID的应用将不再能通过审核,替代的方案是开发者应该使用“在iOS 6中介绍的Vendor或Advertising标示符”。

    4.MAC地址不能再用来设别设备

    **  **还有一个生成iOS设备唯一标示符的方法是使用iOS设备的Media Access Control(MAC)地址。一个MAC地址是一个唯一的号码,它是物理网络层级方面分配给网络适配器的。这个地址苹果还有其他的名字,比如说是硬件地址(Hardware Address)或是Wifi地址,都是指同样的东西。

    有很多工程和框架都使用这个方法来生成唯一的设备ID。比如说ODIN。然而,苹果并不希望有人通过MAC地址来分辨用户,所以如果你在iOS7系统上查询MAC地址,它现在只会返回02:00:00:00:00:00。

    5 **  ** 讲真苹果这傲娇的小脾气什么时候能能改改,不过这样 对于用户隐私的保护,确实起到很大作用,而且苹果也没有把路堵死,现在苹果明确的表明你应该使用-[UIDevice identifierForVendor]或是-[ASIdentifierManager advertisingIdentifier]来作为你框架和应用的唯一标示符。坦白的来说,应对这些变化也不是那么的难,见以下代码片段:

    NSString*identifierForVendor=[[UIDevice currentDevice].identifierForVendor UUIDString];NSString*identifierForAdvertising=[[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];

    但是这样用法有个缺点,就是程序每次被删除以后,获取到的都是新的uuid,并不能实现每个手机的唯一性.

    所以下面要讲的就是这个问题的解决办法.

    **  **对于这个问题有一个可行的办法,就是把获取到的uuid保存在钥匙串里面,这样即使程序删除重装,获取到的uuid一直是同一个,实现了手机的唯一标识的作用.

    保存钥匙串 我们需要用到keychain,除此之外,Code Signing Entitlements的创建方法也不够严谨。下面教大家一种方法,简单快速.

    1.新建一个工程,看一下自己的Bundle Id.这个Bundle Id 要和你用真机测试时的证书上面的Bundle Id相匹配。

     

    注意这个Bundle identifier

    2.Target - Capabilities - Keychain Sharing - ON

     

    注意圆圈里面的保持一致

    这步主要目的是打开Keychain Sharing,将它由灰色状态的OFF改为蓝色状态的ON。

     

    会自动生成这个

    左侧的目录会自动生成Entitlements文件,不需要自己创建了。

    也就是说,Bundle Identifier、Keychain Sharing的Keychain Groups、Entitlements文件的Keychain Access Groups的第一个元素,它们要保持上图所示的一致性。

    设置好了以后可以运行下程序,没问题可以进行下一步。

    .传说中的uuid类和keychain类来啦

    既然苹果的keychain方法会崩溃而且有些复杂,我们只保存一个uuid的话可以用下面的简单方法:

    KeyChainStore.h#import@interfaceKeyChainStore:NSObject+(void)save:(NSString*)service data:(id)data;+(id)load:(NSString*)service;+(void)deleteKeyData:(NSString*)service;@end

    KeyChainStore.m////  KeyChainStore.m//  getUUID////  Created by ckl@pmm on 16/9/18.//  Copyright © 2016年 CKLPronetway. All rights reserved.//#import"KeyChainStore.h"@implementationKeyChainStore+(NSMutableDictionary*)getKeychainQuery:(NSString*)service{return[NSMutableDictionary dictionaryWithObjectsAndKeys:(id)kSecClassGenericPassword,(id)kSecClass,service,(id)kSecAttrService,service,(id)kSecAttrAccount,(id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,nil];}+(void)save:(NSString*)service data:(id)data{//Get search dictionaryNSMutableDictionary*keychainQuery=[selfgetKeychainQuery:service];//Delete old item before add new itemSecItemDelete((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 dictionarySecItemAdd((CFDictionaryRef)keychainQuery,NULL);}+(id)load:(NSString*)service{id ret=nil;NSMutableDictionary*keychainQuery=[selfgetKeychainQuery:service];//Configure the search setting//Since in our simple case we are expecting only a single attribute to be returned (the password) we can set the attribute kSecReturnData to kCFBooleanTrue[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);returnret;}+(void)deleteKeyData:(NSString*)service{NSMutableDictionary*keychainQuery=[selfgetKeychainQuery:service];SecItemDelete((CFDictionaryRef)keychainQuery);}@end

    getUUID.h#import@interfacegetUUID:NSObject+(NSString*)getUUID;@end

    getUUID.m////  getUUID.m//  getUUID////  Created by ckl@pmm on 16/9/18.//  Copyright © 2016年 CKLPronetway. All rights reserved.//#import"getUUID.h"#import"KeyChainStore.h"#defineKEY_USERNAME_PASSWORD @"com.company.app.usernamepassword"#defineKEY_USERNAME @"com.company.app.username"#defineKEY_PASSWORD @"com.company.app.password"@implementationgetUUID+(NSString*)getUUID{NSString*strUUID=(NSString*)[KeyChainStore load:@"com.company.app.usernamepassword"];//首次执行该方法时,uuid为空if([strUUID isEqualToString:@""]||!strUUID){//生成一个uuid的方法CFUUIDRef uuidRef=CFUUIDCreate(kCFAllocatorDefault);strUUID=(NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault,uuidRef));//将该uuid保存到keychain[KeyChainStore save:KEY_USERNAME_PASSWORD data:strUUID];}returnstrUUID;}@end

    在Viewcontroller里面执行如下代码

    #import"ViewController.h"#import"getUUID.h"@interfaceViewController()@end@implementationViewController-(void)viewDidLoad{[superviewDidLoad];NSLog(@" uuid  is  ---> %@",[getUUID getUUID]);// Do any additional setup after loading the view, typically from a nib.}

    打印出来类似于以下的长串字符:

     

    获取到的uuid.png

    把程序卸载掉然后重新运行一次,获取到的还是上次保存的uuid.

    不知道手机越狱以后,会不会改变,因为楼主手机版本是最新的9.3.5,身边还没相关越狱设备,希望大家可以自行测试一下.并告知楼主.联系方式 : QQ :576484150

    参考地址:

    :http://blog.sina.com.cn/s/blog_5971cdd00102vqgy.html

    :http://blog.csdn.net/chy555chy/article/details/51628079

    :https://www.jianshu.com/p/29572b756d26

    写了一个demo,已经放在gitHub上了,有兴趣的同学可以下载下来瞅瞅.

    demo 地址 :https://github.com/chengkunlun/getUUID

  • 相关阅读:
    rs
    stm32f767 usoc3
    stm32f767 RTT 日志
    stm32f767 标准库 工程模板
    stm32f767 HAL 工程模板
    docker tab 补全 linux tab 补全
    docker anconda 依赖 下载 不了
    docker run 常用 指令
    linux scp 命令
    Dockerfile 常用参数说明
  • 原文地址:https://www.cnblogs.com/striveLD/p/12843570.html
Copyright © 2011-2022 走看看