ios 14版本直接获取 idfa,idfv,UUID等 不可靠。
策略是将获取到的idfa,idfv或生成的UUID存储到keychain。
获取UUID代码:
obf_DeviceUUID_fuc.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface obf_DeviceUUID_fuc : NSObject//获取IDFA
+ (NSString *)getIDFA;
//获取IDFV
+ (NSString *)getIDFV;
//获取UUID
//+ (NSString *)getUUID;
//获取UQID
+ (NSString *)getUQID;
@end
obf_DeviceUUID_fuc.m
#import "obf_DeviceUUID_fuc.h"
#import "obf_KeyChain_fuc.h"
#import <AdSupport/ASIdentifierManager.h>
#define UQID_KEY @"com.xxx.device.uqid"
@implementation obf_DeviceUUID_fuc
//获取IDFA
+ (NSString *)getIDFA
{
return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}
//获取IDFV
+ (NSString *)getIDFV
{
return [[UIDevice currentDevice].identifierForVendor UUIDString];
}
//获取UUID
+ (NSString *)getUUID
{
return [[NSUUID UUID] UUIDString];
}
//获取UQID
+ (NSString *)getUQID
{
//从本地沙盒取
NSString *uqid = [[NSUserDefaults standardUserDefaults] objectForKey:UQID_KEY];
if (!uqid) {
//从keychain取
uqid = (NSString *)[obf_KeyChain_fuc readObjectForKey:UQID_KEY];
if (uqid) {
[[NSUserDefaults standardUserDefaults] setObject:uqid forKey:UQID_KEY];
[[NSUserDefaults standardUserDefaults] synchronize];
} else {
//从pasteboard取
// UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
// id data = [pasteboard dataForPasteboardType:UQID_KEY];
// if (data) {
// uqid = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// }
// if (uqid) {
// [[NSUserDefaults standardUserDefaults] setObject:uqid forKey:UQID_KEY];
// [[NSUserDefaults standardUserDefaults] synchronize];
// [obf_KeyChain_fuc saveObject:uqid forKey:UQID_KEY];
// } else {
//获取idfa
uqid = [self getIDFA];
//idfa获取失败的情况,获取idfv
if (!uqid || [uqid isEqualToString:@"00000000-0000-0000-0000-000000000000"]) {
uqid = [self getIDFV];
//idfv获取失败的情况,获取uuid
if (!uqid) {
uqid = [self getUUID];
}
// }
[[NSUserDefaults standardUserDefaults] setObject:uqid forKey:UQID_KEY];
[[NSUserDefaults standardUserDefaults] synchronize];
[obf_KeyChain_fuc saveObject:uqid forKey:UQID_KEY];
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
NSData *data = [uqid dataUsingEncoding:NSUTF8StringEncoding];
[pasteboard setData:data forPasteboardType:UQID_KEY];
}
}
}
return uqid;
}
@end
操作keychain代码:
obf_KeyChain_fuc.h
#import <Foundation/Foundation.h>
@interface obf_KeyChain_fuc : NSObject
+ (void)saveObject:(id)object forKey:(NSString *)key;
+ (id)readObjectForKey:(NSString *)key;
+ (void)deleteObjectForKey:(NSString *)key;
+ (void)deleteAllObject;
@end
@interface SaveKeyChain : NSObject
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service;
+ (void)save:(NSString *)service data:(id)data;
+ (id)load:(NSString *)service;
+ (void)delete:(NSString *)service;
@end
obf_KeyChain_fuc.m
#import "obf_KeyChain_fuc.h"
#define BUNDLE_ID [[NSBundle mainBundle] bundleIdentifier]
@implementation obf_KeyChain_fuc
+ (void)saveObject:(id)object forKey:(NSString *)key {
NSMutableDictionary *mDic = [NSMutableDictionary dictionary];
[mDic setValuesForKeysWithDictionary:(NSMutableDictionary *)[SaveKeyChain load:BUNDLE_ID]];
[mDic setObject:object forKey:key];
[SaveKeyChain save:BUNDLE_ID data:mDic];
}
+ (id)readObjectForKey:(NSString *)key {
NSMutableDictionary *mDic = (NSMutableDictionary *)[SaveKeyChain load:BUNDLE_ID];
return [mDic objectForKey:key];
}
+ (void)deleteObjectForKey:(NSString *)key {
NSMutableDictionary *mDic = (NSMutableDictionary *)[SaveKeyChain load:BUNDLE_ID];
[mDic removeObjectForKey:key];
[SaveKeyChain save:BUNDLE_ID data:mDic];
}
+ (void)deleteAllObject {
[SaveKeyChain delete:BUNDLE_ID];
}
@end
@implementation SaveKeyChain
+ (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];
}
+ (void)save:(NSString *)service data:(id)data {
//Get search dictionary
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
//Delete old item before add new item
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
//Add new object to search dictionary(Attention:the data format)
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
//Add item to keychain with the search dictionary
SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
}
+ (id)load:(NSString *)service {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
//Configure the search setting
[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;
}
+ (void)delete:(NSString *)service {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}
@end
ios14 需要添加添加keychainsharing:
在Signing & Capabilities界面点+Capability双击钥匙图标
点Keychain Groups框下边的+号会自动填上包名。