iOS 唯一识别码 IDFV+keychain

2017-09-07  本文已影响127人  frankyfz

这段时间用到了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

上一篇下一篇

猜你喜欢

热点阅读