這段時間用到了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