標籤:
今天博主有一個擷取裝置唯一標識的需求,遇到了一些困痛點,在此和大家分享,希望能夠共同進步.
在iOS7.0之前,擷取裝置唯一標識的方法主要是擷取UDID或MAC地址,但是在iOS7.0之後,為了保護使用者隱私,蘋果把他們都禁止了,使得裝置的資料追蹤變得越來越難.
iOS7.0之後,擷取裝置唯一標識的方法主要有兩種:
1.廣告標識符 IDFA
蘋果為了完善自己的生態圈,在2010年前後推出了iAd廣告網路。那麼這個IDFA和這個iAd的關係就不言自喻了。如果不瞭解廣告也沒關係,簡單來講,現在的互連網廣告精準投放需要瞭解使用者資料,基於這些資訊使得廣告更有效率,唯一標識就很重要,就用到了IDFA.
advertisingIdentifier在AdSupport.framework的ASIdentifierManager類中,是其中兩個屬性中的一個.
可以說,用這個IDFA標識裝置應該還是很精準的(不然iAd就徹底不用玩了),很多開發人員還在使用.
2.IDFV+Key Chain
由於IDFV刪除app之後再重新安裝,標識符就變了,要解決這個問題,可以把第一次產生的ID儲存到Key Chain中,刪除app之後Key Chain中的資料還在就OK了.
#define KEY_UDID @"KEY_UDID"
#define KEY_IN_KEYCHAIN @"KEY_IN_KEYCHAIN"
#import <Security/Security.h>
#import "APPIdentificationManage.h"
@implementation APPIdentificationManage
singleton_implementation(APPIdentificationManage)
#pragma mark 擷取UUID
/**
*此uuid在相同的一個程式裡面-相同的vindor-相同的裝置下是不會改變的
*此uuid是唯一的,但應用刪除再重新安裝後會變化,採取的措施是:只擷取一次儲存在鑰匙串中,之後就從鑰匙串中擷取
**/
- (NSString *)openUDID
{
NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString];
return identifierForVendor;
}
#pragma mark 儲存UUID到鑰匙串
- (void)saveUDID:(NSString *)udid
{
NSMutableDictionary *udidKVPairs = [NSMutableDictionary dictionary];
[udidKVPairs setObject:udid forKey:KEY_UDID];
[[APPIdentificationManage sharedAPPIdentificationManage] save:KEY_IN_KEYCHAIN data:udidKVPairs];
}
#pragma mark 讀取UUID
/**
*先從記憶體中擷取uuid,如果沒有再從鑰匙串中擷取,如果還沒有就產生一個新的uuid,並儲存到鑰匙串中供以後使用
**/
- (id)readUDID
{
if (_uuid == nil || _uuid.length == 0) {
NSMutableDictionary *udidKVPairs = (NSMutableDictionary *)[[APPIdentificationManage sharedAPPIdentificationManage] load:KEY_IN_KEYCHAIN];
NSString *uuid = [udidKVPairs objectForKey:KEY_UDID];
if (uuid == nil || uuid.length == 0) {
uuid = [self openUDID];
[self saveUDID:uuid];
}
_uuid = uuid;
}
return _uuid;
}
#pragma mark 刪除UUID
- (void)deleteUUID
{
[APPIdentificationManage delete:KEY_IN_KEYCHAIN];
}
#pragma mark 查詢鑰匙串
- (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys: (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass, service, (__bridge_transfer id)kSecAttrService, service,(__bridge_transfer id)kSecAttrAccount, (__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible, nil nil];
}
#pragma mark 將資料儲存到鑰匙串
- (void)save:(NSString *)service data:(id)data {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
}
#pragma mark 載入鑰匙串中資料
- (id)load:(NSString *)service {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];
[keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
@try {
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
} @catch (NSException *e) {
NSLog(@"Unarchive of %@ failed: %@", service, e);
} @finally {
}
}
return ret;
}
#pragma mark 刪除鑰匙串中資料
- (void)delete:(NSString *)service {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}
@end
iOS開發日記20-7.0之後擷取裝置唯一標識