这段时间用到了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 到这里就结束了  希望可以让阅读者节省点时间