IOS设备唯一标识设置策略

2,175 阅读2分钟

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框下边的+号会自动填上包名。