在很多场景中,我们需要获取设备的唯一标识,用来做定点推送等操作,那么这时候我们就需要精准到某台手机,甚至某个人,客户端这边就需要保证这个标识具有唯一性,并且即使我们的APP卸载重装了,也能够保持不变。
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:域名注册、网络空间、营销软件、网站建设、栾城网站维护、网站推广。
在iOS5以前,大家普遍使用的是UDID,可iOS5以后苹果就把UDID的访问权限移除了,而且试图访问UDID的程序在审核的时候很大几率都会被拒。所以使用UDID作为唯一标识的路就行不通了。
还有人说,UUID也可以作为唯一标识,确实,但是,有一个不好的地方就是每次获取设备的UUID都会是一个新的与上次不同的值,所以这个也行不通。
还有一个Open UDID,但是这个库已经弃用了,而且这个值在APP卸载重装后获得的值也会不同。
此外,广告标志符IDFA,也曾被人用作唯一标识,但是这个在重置系统或者还原广告标志符后获取到的值也会不同。
那么,我们又将如何获取iOS设备的唯一标识呢?
解决方案:
在APP第一次运行的时候,使用keychain存储一个标识,然后在接下来访问的时候直接从keychain中取。这样做的好处在于,keychain中的数据会被同步到iCloud中,即使删除了应用也会存在。但是这样做也有一个不好的地方,就是如果多台手机使用了同一个iCloud账号登录,那么这个唯一标识将毫无意义。
不过,话又说回来,任何一种技术的实现都有自己的应用场景,比如上面这个既然是同一个iCloud账号就看做是同一个账号。所以,如何标记iOS设备还得看具体的需求。
参考文章 iOS唯一标识符(IDFAIDFV)
依赖: AdSupport.framework
系统支持: iOS6及以上系统
获取方式: [ASIdentifierManager sharedManager].advertisingIdentifier.UUIDString
定义: 由数字和字母组成的用来标识唯一设备的字符串。
特点:
依赖: UIKit.framework
系统支持: iOS6及以上系统
获取方式: [UIDevice currentDevice].identifierForVendor.UUIDString
定义: 由数字和字母组成的用来标识唯一设备的字符串。
特点: 根据vendor的值,如果vendor相同,则返回同一字符串;如果vendor不同,则返回不同的字符串。
vendor解释: 英文解释为卖家,小贩。根据xcode文档解释,正常情况下,会根据App Store提供的数据进行判断。但是如果app不是通过app store进行安装的(如企业应用或开发调试阶段),那么会根据bundle ID判断。
判断准则:
如:com.example.app1和com.example.app2,只有最后的后缀不同,所以会产生相同的vendor ID
在这里,还需要注意的一点就是:如果用户卸载了同一个vendor对应的所有程序,然后在重新安装同一个vendor提供的程序,此时identifierForVendor会被重置。
- ( void )uniqueMarkDemo{
/**
原UDID已经废弃。。不在叙述
NSUUID在iOS 6中才出现 每次调用的时候都会获得一个新的唯一标示符。如果要存储的话,你需要自己存储。*/
NSString*uuid = [[NSUUIDUUID]UUIDString];
/**
广告标示符,在同一个设备上的所有App都会取到相同的值,是苹果专门给各广告提供商用来追踪用户而设的。由系统存储着的
如果用户完全重置系统、还原广告广告标示符也会重新生成。
所以IDFA也不可以作为获取唯一标识的方法,来识别用户。
*/
NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
/***
同一个Vender(应用提供商,实际BundleID的前两部分进行匹配,如对于com.taobao.appA, com.taobao.appB 属于同一个Vender)的应用里,都有相同的值。和IDFA不同的是,IDFV的值是一定能取到的,所以非常适合于作为内部用户行为分析的主id
但是如果用户将属于此Vender的所有App卸载,则IDFV的值会被重置,更新
*/
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
/**
KeyChain共享数据 KeyChain理解为一个Dictionary,add、update、get、delete这四个操作,KeyChain都有两个访问区,私有区和公共区。默认APP1只能访问app1的内容,对其他程序不可见。如果想共享内容,需要先声明公共区的名称,同时打开keychain-sharing配置。。官方文档管这个名称叫“keychain access group”,声明的方法是新建一个plist文件,名字随便起,内容如下:
keychain-access-groups Array 1item
item 0 String myAppId.com.mycompany.any
除了any字段,其他的如实填写。这个文件的路径要配置在 Project-build setting-Code Signing Entitlements里,否则公共区无效,配置好后,须用你正式的证书签名编译才可通过,否则xcode会弹框告诉你code signing有问题。所以,苹果限制了你只能同公司的产品共享KeyChain数据,别的公司访问不了你公司产品的KeyChain。
这部分更详细的往上很多。。可以参考
*/
/***
最后;存储唯一表示我们应用UUID + keychain方式
将获取的UUID存储本地,同时存储KeyChain中, 每次取的时候, 检查本地、钥匙串中有没有, 如果没有则需要将获取的UUID存储进去。但是如果设备刷机时, KeyChain会清空。
案例:引入三方工具SAMKeychain
*/
//全局Userdefault key
#define KV_UUID_STR @"KV_UUID_STR"
#define KV_KEYCHAIN_ACCOUNT @"com.mycompany.iosapp.A"
[ self getUuidStr];
}
- (NSString*)getUuidStr {
NSString *uuidstr = [[NSUserDefaults standardUserDefaults] objectForKey:KV_UUID_STR];
if (uuidstr uuidstr.length0) {
return uuidstr;
} else {
NSString*keychainStr = [SAMKeychain passwordForService:KV_UUID_STRaccount:KV_KEYCHAIN_ACCOUNT];
if (keychainStr keychainStr.length0) {
[[NSUserDefaults standardUserDefaults] setObject:keychainStr forKey:KV_UUID_STR];
return keychainStr;
} else {
NSString*newUuid = [ self uuidString];
if (newUuid newUuid.length0) {
[[NSUserDefaults standardUserDefaults] setObject:newUuid forKey:KV_UUID_STR];
[SAMKeychain setPassword:newUuid forService:KV_UUID_STRaccount:KV_KEYCHAIN_ACCOUNT];
}
return newUuid;
}
}
}
- (NSString *)uuidString
{
CFUUIDRefuuid_ref =CFUUIDCreate( NULL );
CFStringRefuuid_string_ref=CFUUIDCreateString( NULL , uuid_ref);
NSString*uuid = [NSStringstringWithString:( __bridge NSString*)uuid_string_ref];
CFRelease(uuid_ref);
CFRelease(uuid_string_ref);
return [uuid lowercaseString];
}
设备唯一标识UDID被弃用后的一种替代方法,生成一个随机数--UUID,并用KeyChain存储,这样就可以保证程序卸载重装时,这个UUID不变,这UUID就可以作为我们的设备唯一标识。
注意 : 刷机 或者 升级系统 后的情况,UUID还是会改变的。
先导入QCUUID.h