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 <AdSupport/ASIdentifierManager.h>

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  

posted @ 2016-07-26 17:01  废话太多不如沉默  阅读(6058)  评论(0编辑  收藏  举报