iOS 唯一识别码 IDFV+keychain
这段时间用到了iPhone的唯一标识,找到了不少方法,认为较好用的且现在可行的有两种。一是IDFV另一个是IDFA,前者identifierForVendor是apple给供应商唯一的一个值,也就是说同一个公司发行的的app在相同的设备上运行的时候会有这个相同的标识符。然而,如果用户删除了这个供应商的所有app然后再重新安装的话,这个标识符就会不一致。后者advertisingIdentifier则是给在这个设备上所有软件供应商相同的一个值,一般在广告的时候使用。这个值虽然不会因为重装app改变,但是在某些情况下还是会改变。如果用户完全重置系统((设置程序 -> 通用 -> 还原 -> 还原位置与隐私) ,这个广告标示符会重新生成。另外如果用户明确的还原广告(设置程序-> 通用 -> 关于本机 -> 广告 -> 还原广告标示符) ,那么广告标示符也会重新生成。关于广告标示符的还原,还有一点需要注意:如果程序在后台运行,此时用户“还原广告标示符”,然后再回到程序中,此时获取广告标示符并不会立即获得还原后的标示符。必须要终止程序,然后再重新启动程序,才能获得还原后的广告标示符。
获取方法如下:
NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString];
NSString *identifierForAdvertising = [[ASIdentifierManager sharedManager].advertisingIdentifier UUIDString];
相比卸载重装,IDFA还是较稳定的,但是用IDFA在送审的时候,要表明用了广告标识符,并且要导入依赖库,为了不引起必要麻烦,本人采用了IDFV+keychain的方法。keychain是iPhone的一个机制。将信息保存在系统,这些信息不随app的卸载重装而消失。
先简单介绍下IDFA的导入方法:
---------------------------------------------------------------------------
1、添加框架 本人刚开始导入的是security.framework 测试也可以使用
AdSupport.framework
2、添加头文件
#import
3、使用语句
NSString *IDFA = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
-----------------------------------------------------------------------------
重点是IDFV+keychain这种方法 封装在一个工具类中 非常好用 ok上代码
Tools.h中
+++++++++++++++++++++
+ (void)save:(NSString *)service data:(id)data;
+ (id)load:(NSString *)service;
+ (void)delete:(NSString *)service;
+ (NSString *)getIDFV;
++++++++++++++++++++++
Tools.m中
=================================
+ (NSString *)getIDFV
{
//定义存入keychain中的账号 也就是一个标识 表示是某个app存储的内容 bundle id就好
NSString * const KEY_USERNAME_PASSWORD = @"com.danson.zzzz.usernamepassword";
NSString * const KEY_PASSWORD = @"com.danson.zzzz.password";
//测试用 清除keychain中的内容
//[Tools delete:KEY_USERNAME_PASSWORD];
//读取账号中保存的内容
NSMutableDictionary *readUserPwd = (NSMutableDictionary *)[Tools load:KEY_USERNAME_PASSWORD];
//NSLog(@"keychain------><>%@",readUserPwd);
if (!readUserPwd) {
//如果为空 说明是第一次安装 做存储操作
NSString *identifierStr = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
//NSLog(@"identifierStr-----><>%@",identifierStr);
NSMutableDictionary *usernamepasswordKVPairs = [NSMutableDictionary dictionaryWithObject:identifierStr forKey:KEY_PASSWORD];
[Tools save:KEY_USERNAME_PASSWORD data:usernamepasswordKVPairs];
return identifierStr;
}else{
return [readUserPwd objectForKey:KEY_PASSWORD];
}
}
//储存
+ (void)save:(NSString *)service data:(id)data {
//Get search dictionary
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
//Delete old item before add new item
SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
//Add new object to search dictionary(Attention:the data format)
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
//Add item to keychain with the search dictionary
SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
}
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kSecClassGenericPassword,(__bridge id)kSecClass,
service, (__bridge id)kSecAttrService,
service, (__bridge id)kSecAttrAccount,
(__bridge id)kSecAttrAccessibleAfterFirstUnlock,(__bridge id)kSecAttrAccessible,
nil];
}
//取出
+ (id)load:(NSString *)service {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery: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:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
[keychainQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((__bridge 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);
return ret;
}
//删除
+ (void)delete:(NSString *)service {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
}
================================
调用的时候
直接 [Tools getIDFV] 就可以了 暂时还不知道 系统会不会把卸载重装前生成的IDFA给别的开发商 如果会重新分配 就可能会产生重复的 待考证
ok 到这里就结束了 希望可以让阅读者节省点时间
参考资料 http://www.cnblogs.com/qingjoin/p/3549325.html