IDFA(广告标识)
IDFA只支持iOS 6以上
+(NSString *)idfa
{
//这里最好随机生成一个值,在iOS6以上用户关闭获取广告追踪也会造成idfa无法获取
NSString *ad = @"iOS5WithoutIDFA";
if ([[[UIDevice currentDevice] systemVersion] intValue]>=6) {
ad= [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}
return ad;
}
IDFV(推广标识)
IDFA作为推广id,只适用于同Vender下获取到的值相同。即同一个厂商发布的应用
+(NSString *)idfv
{
NSString *ad = @"iOS5WithoutIDFV";
if ([[[UIDevice currentDevice] systemVersion] intValue]>=6) {
ad= [[[UIDevice currentDevice] identifierForVendor] UUIDString];
}
return ad;
}
在UUID被苹果禁用以后,可以用IDFA作为设备的唯一标识。由于IDFA在设置中可以被用户修改或关闭获取权限,一般配合钥匙串(Keychain)使用。
需要添加的系统库
#import <Security/Security.h>
存入钥匙串
+ (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);
}
读取
+ (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:(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;
}
+ (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];
}
最终获取设备唯一标识的方法
+(NSString *)getUniqueIdentifier
{
NSMutableDictionary *idfvKVPairs = (NSMutableDictionary *)[LKIADKeychain load:RK_KEY_DEVICE_IDENTIFIER_PASSWORD];
NSString *ad = [idfvKVPairs objectForKey:RK_KEY_IDENTIFIER];
if ([ad length]<3) {
idfvKVPairs = [NSMutableDictionary dictionary];
ad = [LKIADDDeviceIdentifier idfa];
if ([ad length]<3) {
ad = [self createUUID];
}
[idfvKVPairs setObject:ad forKey:RK_KEY_IDENTIFIER];
[LKIADKeychain save:RK_KEY_DEVICE_IDENTIFIER_PASSWORD data:idfvKVPairs];
}
return ad;
}
在其他设备中常用作为唯一标识的mac地址也不适用iOS,在iOS7以上的设备中获取到的是固定值 02:00:00:00:00:00
mac地址获取方法
+(NSString *) macaddress
{
int mib[6];
size_t len;
char *buf;
unsigned char *ptr;
struct if_msghdr *ifm;
struct sockaddr_dl *sdl;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = AF_LINK;
mib[4] = NET_RT_IFLIST;
if ((mib[5] = if_nametoindex("en0")) == 0) {
printf("Error: if_nametoindex error/n");
return NULL;
}
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
printf("Error: sysctl, take 1/n");
return NULL;
}
if ((buf = malloc(len)) == NULL) {
printf("Could not allocate memory. error!/n");
return NULL;
}
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
printf("Error: sysctl, take 2");
return NULL;
}
ifm = (struct if_msghdr *)buf;
sdl = (struct sockaddr_dl *)(ifm + 1);
ptr = (unsigned char *)LLADDR(sdl);
NSString *outstring = [NSString stringWithFormat:@"%02x.%02x.%02x.%02x.%02x.%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
free(buf);
NSString *mac= [outstring uppercaseString];
return mac;
}