iOS获取设备唯一标识
2017-08-04 14:49
501 查看
在开发中会遇到应用需要记录设备标示,即使应用卸载后再安装也可重新识别的情况,在这写一种实现方式——读取设备的UUID(Universally Unique Identifier)并通过KeyChain记录。
首先iOS中获取设备唯一标示符的方法一直随版本的更新而变化。iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符的方法uniqueIdentifier,通过该方法我们可以获取设备的序列号,这个也是目前为止唯一可以确认唯一的标示符。好景不长,因为该唯一标识符与手机一一对应,苹果觉得可能会泄露用户隐私,所以在 iOS 5.0之后该方法就被废弃掉了;iOS
6.0系统新增了两个用于替换uniqueIdentifier的接口,分别是:identifierForVendor,advertisingIdentifier,但这两个接口会在应用重新安装时改变数值,并不是唯一的标示符,所以开发者改为使用WiFi的mac地址来取代;iOS 7中苹果又封杀mac地址,所以开发者再次改变思路使用KeyChain来保存获取到的UDID,这样以后即使APP删了再装回来,也可以从KeyChain中读取回来。
iOS的keychain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keychain存储。相对于NSUserDefaults、文件保存等一般方式,keychain保存更为安全,而且keychain里保存的信息不会因App被删除而丢失。
//
// YKeychain.h
//
//
// Created by CJW on 17/8/4.
// Copyright © 2017年 onight. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface YKeychain : NSObject
NS_ASSUME_NONNULL_BEGIN
+ (BOOL)setValue:(id)value forKey:(NSString *)key;
+ (BOOL)setValue:(id)value forKey:(NSString *)key forAccessGroup:(nullable
NSString *)group;
+ (id)valueForKey:(NSString *)key;
+ (id)valueForKey:(NSString *)key forAccessGroup:(nullable
NSString *)group;
+ (BOOL)deleteValueForKey:(NSString *)key;
+ (BOOL)deleteValueForKey:(NSString *)key forAccessGroup:(nullable
NSString *)group;
+ (NSString *)getBundleSeedIdentifier;
@end
NS_ASSUME_NONNULL_END
//
// YKeychain
//
//
// Created by CJW on 17/8/4.
// Copyright © 2017年 onight. All rights reserved.
//
#import "YKeychain.h"
@implementation YKeychain
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)key forAccessGroup:(NSString
*)group{
NSMutableDictionary *query =
@{(__bridge
id)kSecClass : (__bridge
id)kSecClassGenericPassword,
(__bridge
id)kSecAttrService : key,
(__bridge
id)kSecAttrAccount : key,
(__bridge
id)kSecAttrAccessible : (__bridge
id)kSecAttrAccessibleAfterFirstUnlock
}.mutableCopy;
if (group !=
nil) {
[query setObject:[self
getFullAccessGroup:group]
forKey:(__bridge
id)kSecAttrAccessGroup];
}
return query;
}
+ (NSString *)getFullAccessGroup:(NSString *)group
{
NSString *accessGroup =
nil;
NSString *bundleSeedIdentifier = [self
getBundleSeedIdentifier];
if (bundleSeedIdentifier !=
nil && [group rangeOfString:bundleSeedIdentifier].location ==
NSNotFound) {
accessGroup = [NSString
stringWithFormat:@"%@.%@", bundleSeedIdentifier, group];
}
return accessGroup;
}
+ (NSString *)getBundleSeedIdentifier
{
static
__strong NSString *bundleSeedIdentifier =
nil;
if (bundleSeedIdentifier ==
nil) {
@synchronized(self) {
if (bundleSeedIdentifier ==
nil) {
NSString *_bundleSeedIdentifier =
nil;
NSDictionary *query =
@{
(__bridge
id)kSecClass: (__bridge
NSString *)kSecClassGenericPassword,
(__bridge
id)kSecAttrAccount:
@"bundleSeedID",
(__bridge
id)kSecAttrService:
@"",
(__bridge
id)kSecReturnAttributes: (__bridge
id)kCFBooleanTrue
};
CFDictionaryRef result =
nil;
OSStatus status =
SecItemCopyMatching((__bridge
CFDictionaryRef)query, (CFTypeRef *)&result);
if (status ==
errSecItemNotFound) {
status = SecItemAdd((__bridge
CFDictionaryRef)query, (CFTypeRef *)&result);
}
if (status ==
errSecSuccess) {
NSString *accessGroup = [(__bridge
NSDictionary *)result
objectForKey:(__bridge
NSString *)kSecAttrAccessGroup];
NSArray *components = [accessGroup
componentsSeparatedByString:@"."];
_bundleSeedIdentifier = [[components objectEnumerator]
nextObject];
CFRelease(result);
}
if (_bundleSeedIdentifier !=
nil) {
bundleSeedIdentifier = [_bundleSeedIdentifier
copy];
}
}
}
}
return bundleSeedIdentifier;
}
+ (BOOL)setValue:(id)value forKey:(NSString *)key{
return [self setValue:value forKey:key forAccessGroup:nil];
}
+ (BOOL)setValue:(id)value forKey:(NSString *)key forAccessGroup:(NSString *)group{
NSMutableDictionary *query = [self getKeychainQuery:key forAccessGroup:group];
[self deleteValueForKey:key forAccessGroup:group];
NSData *data = nil;
@try {
data = [NSKeyedArchiver archivedDataWithRootObject:value];
} @catch (NSException *exception) {
return
NO;
}
[query setObject:data forKey:(__bridge
id)kSecValueData];
OSStatus result = SecItemAdd((__bridge CFDictionaryRef)query,
NULL);
return result == errSecSuccess;
}
+ (BOOL)deleteValueForKey:(NSString *)key{
return [self deleteValueForKey:key forAccessGroup:nil];
}
+ (BOOL)deleteValueForKey:(NSString *)key forAccessGroup:(NSString *)group{
NSMutableDictionary *query = [self getKeychainQuery:key forAccessGroup:group];
OSStatus result = SecItemDelete((__bridge CFDictionaryRef)query);
return result == errSecSuccess;
}
+ (id)valueForKey:(NSString *)key{
return [self valueForKey:key forAccessGroup:nil];
}
+ (id)valueForKey:(NSString *)key forAccessGroup:(NSString *)group{
id value =
nil;
NSMutableDictionary *query = [self getKeychainQuery:key forAccessGroup:group];
CFDataRef keyData = NULL;
[query setObject:(__bridge
id)kCFBooleanTrue forKey:(__bridge
id)kSecReturnData];
[query setObject:(__bridge
id)kSecMatchLimitOne forKey:(__bridge
id)kSecMatchLimit];
if (SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&keyData) == errSecSuccess) {
@try {
value = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
}
@catch (NSException *e) {
value = nil;
}
}
if (keyData) {
CFRelease(keyData);
}
return value;
}
@end
//
// XCKeyChain.h
//
//
// Created by CJW on 17/8/4.
// Copyright © 2017年 onight. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface XCKeyChain :
NSObject
+(void)setKeyUUID:(NSString *)str;
+(NSString*)getKeyUUID;
@end
//
// XCKeyChain.m
// zjfae
//
// Created by CJW on 17/8/4.
// Copyright © 2017年 onight. All rights reserved.
//
#import "XCKeyChain.h"
#import "YKeychain.h"
static NSString *
const accessGroup =
@"com.zjfae.uuidKey";
@implementation XCKeyChain
+(void)setKeyUUID:(NSString *)str{
[YKeychain
setValue:str
forKey:accessGroup];
}
+(NSString*)getKeyUUID{
NSString * uuidStr = [YKeychain
valueForKey:accessGroup];
if(uuidStr ==
nil){
return
@"";
}else{
return uuidStr;
}
}
@end
由于用的是swift写的项目所以这里用swift调用;
/// 保存用户UUID
class
func saveUserUUID(str:String){
XCKeyChain.setKeyUUID(str)
}
class
func getUserUUID() ->
String {
return XCKeyChain.getKeyUUID()
}
参照简书:http://www.jianshu.com/p/354ea1279e68
首先iOS中获取设备唯一标示符的方法一直随版本的更新而变化。iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符的方法uniqueIdentifier,通过该方法我们可以获取设备的序列号,这个也是目前为止唯一可以确认唯一的标示符。好景不长,因为该唯一标识符与手机一一对应,苹果觉得可能会泄露用户隐私,所以在 iOS 5.0之后该方法就被废弃掉了;iOS
6.0系统新增了两个用于替换uniqueIdentifier的接口,分别是:identifierForVendor,advertisingIdentifier,但这两个接口会在应用重新安装时改变数值,并不是唯一的标示符,所以开发者改为使用WiFi的mac地址来取代;iOS 7中苹果又封杀mac地址,所以开发者再次改变思路使用KeyChain来保存获取到的UDID,这样以后即使APP删了再装回来,也可以从KeyChain中读取回来。
iOS的keychain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keychain存储。相对于NSUserDefaults、文件保存等一般方式,keychain保存更为安全,而且keychain里保存的信息不会因App被删除而丢失。
//
// YKeychain.h
//
//
// Created by CJW on 17/8/4.
// Copyright © 2017年 onight. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface YKeychain : NSObject
NS_ASSUME_NONNULL_BEGIN
+ (BOOL)setValue:(id)value forKey:(NSString *)key;
+ (BOOL)setValue:(id)value forKey:(NSString *)key forAccessGroup:(nullable
NSString *)group;
+ (id)valueForKey:(NSString *)key;
+ (id)valueForKey:(NSString *)key forAccessGroup:(nullable
NSString *)group;
+ (BOOL)deleteValueForKey:(NSString *)key;
+ (BOOL)deleteValueForKey:(NSString *)key forAccessGroup:(nullable
NSString *)group;
+ (NSString *)getBundleSeedIdentifier;
@end
NS_ASSUME_NONNULL_END
//
// YKeychain
//
//
// Created by CJW on 17/8/4.
// Copyright © 2017年 onight. All rights reserved.
//
#import "YKeychain.h"
@implementation YKeychain
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)key forAccessGroup:(NSString
*)group{
NSMutableDictionary *query =
@{(__bridge
id)kSecClass : (__bridge
id)kSecClassGenericPassword,
(__bridge
id)kSecAttrService : key,
(__bridge
id)kSecAttrAccount : key,
(__bridge
id)kSecAttrAccessible : (__bridge
id)kSecAttrAccessibleAfterFirstUnlock
}.mutableCopy;
if (group !=
nil) {
[query setObject:[self
getFullAccessGroup:group]
forKey:(__bridge
id)kSecAttrAccessGroup];
}
return query;
}
+ (NSString *)getFullAccessGroup:(NSString *)group
{
NSString *accessGroup =
nil;
NSString *bundleSeedIdentifier = [self
getBundleSeedIdentifier];
if (bundleSeedIdentifier !=
nil && [group rangeOfString:bundleSeedIdentifier].location ==
NSNotFound) {
accessGroup = [NSString
stringWithFormat:@"%@.%@", bundleSeedIdentifier, group];
}
return accessGroup;
}
+ (NSString *)getBundleSeedIdentifier
{
static
__strong NSString *bundleSeedIdentifier =
nil;
if (bundleSeedIdentifier ==
nil) {
@synchronized(self) {
if (bundleSeedIdentifier ==
nil) {
NSString *_bundleSeedIdentifier =
nil;
NSDictionary *query =
@{
(__bridge
id)kSecClass: (__bridge
NSString *)kSecClassGenericPassword,
(__bridge
id)kSecAttrAccount:
@"bundleSeedID",
(__bridge
id)kSecAttrService:
@"",
(__bridge
id)kSecReturnAttributes: (__bridge
id)kCFBooleanTrue
};
CFDictionaryRef result =
nil;
OSStatus status =
SecItemCopyMatching((__bridge
CFDictionaryRef)query, (CFTypeRef *)&result);
if (status ==
errSecItemNotFound) {
status = SecItemAdd((__bridge
CFDictionaryRef)query, (CFTypeRef *)&result);
}
if (status ==
errSecSuccess) {
NSString *accessGroup = [(__bridge
NSDictionary *)result
objectForKey:(__bridge
NSString *)kSecAttrAccessGroup];
NSArray *components = [accessGroup
componentsSeparatedByString:@"."];
_bundleSeedIdentifier = [[components objectEnumerator]
nextObject];
CFRelease(result);
}
if (_bundleSeedIdentifier !=
nil) {
bundleSeedIdentifier = [_bundleSeedIdentifier
copy];
}
}
}
}
return bundleSeedIdentifier;
}
+ (BOOL)setValue:(id)value forKey:(NSString *)key{
return [self setValue:value forKey:key forAccessGroup:nil];
}
+ (BOOL)setValue:(id)value forKey:(NSString *)key forAccessGroup:(NSString *)group{
NSMutableDictionary *query = [self getKeychainQuery:key forAccessGroup:group];
[self deleteValueForKey:key forAccessGroup:group];
NSData *data = nil;
@try {
data = [NSKeyedArchiver archivedDataWithRootObject:value];
} @catch (NSException *exception) {
return
NO;
}
[query setObject:data forKey:(__bridge
id)kSecValueData];
OSStatus result = SecItemAdd((__bridge CFDictionaryRef)query,
NULL);
return result == errSecSuccess;
}
+ (BOOL)deleteValueForKey:(NSString *)key{
return [self deleteValueForKey:key forAccessGroup:nil];
}
+ (BOOL)deleteValueForKey:(NSString *)key forAccessGroup:(NSString *)group{
NSMutableDictionary *query = [self getKeychainQuery:key forAccessGroup:group];
OSStatus result = SecItemDelete((__bridge CFDictionaryRef)query);
return result == errSecSuccess;
}
+ (id)valueForKey:(NSString *)key{
return [self valueForKey:key forAccessGroup:nil];
}
+ (id)valueForKey:(NSString *)key forAccessGroup:(NSString *)group{
id value =
nil;
NSMutableDictionary *query = [self getKeychainQuery:key forAccessGroup:group];
CFDataRef keyData = NULL;
[query setObject:(__bridge
id)kCFBooleanTrue forKey:(__bridge
id)kSecReturnData];
[query setObject:(__bridge
id)kSecMatchLimitOne forKey:(__bridge
id)kSecMatchLimit];
if (SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&keyData) == errSecSuccess) {
@try {
value = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
}
@catch (NSException *e) {
value = nil;
}
}
if (keyData) {
CFRelease(keyData);
}
return value;
}
@end
//
// XCKeyChain.h
//
//
// Created by CJW on 17/8/4.
// Copyright © 2017年 onight. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface XCKeyChain :
NSObject
+(void)setKeyUUID:(NSString *)str;
+(NSString*)getKeyUUID;
@end
//
// XCKeyChain.m
// zjfae
//
// Created by CJW on 17/8/4.
// Copyright © 2017年 onight. All rights reserved.
//
#import "XCKeyChain.h"
#import "YKeychain.h"
static NSString *
const accessGroup =
@"com.zjfae.uuidKey";
@implementation XCKeyChain
+(void)setKeyUUID:(NSString *)str{
[YKeychain
setValue:str
forKey:accessGroup];
}
+(NSString*)getKeyUUID{
NSString * uuidStr = [YKeychain
valueForKey:accessGroup];
if(uuidStr ==
nil){
return
@"";
}else{
return uuidStr;
}
}
@end
由于用的是swift写的项目所以这里用swift调用;
/// 保存用户UUID
class
func saveUserUUID(str:String){
XCKeyChain.setKeyUUID(str)
}
class
func getUserUUID() ->
String {
return XCKeyChain.getKeyUUID()
}
参照简书:http://www.jianshu.com/p/354ea1279e68
相关文章推荐
- 获取iOS设备唯一标识 uuid
- iOS获取设备唯一标识的各种方法?IDFA、IDFV、UDID分别是什么含义?
- iOS获取设备唯一标识的各种方法?IDFA、IDFV、UDID分别是什么含义?
- ios设备唯一标识获取策略
- ios设备唯一标识获取策略
- ios设备唯一标识获取策略
- ios设备唯一标识获取策略
- 获取iOS设备唯一标识
- Unity3d获取IOS设备唯一标识,以及IDFA
- iOS 获取设备唯一标识
- iOS开发中如何获取设备唯一标识
- ios设备唯一标识获取策略
- 【IOS】获取iOS设备唯一标识的演进UDID, MAC Address,UUID,IDFA,IDFV,OpenUDID
- ios设备唯一标识获取策略
- iOS设备唯一标识获取策略
- iOS -- 设备唯一标识获取策略(最全最详细)
- iOS 设备唯一标识的获取
- ios设备唯一标识获取策略
- 获取iOS设备唯一标识
- ios设备唯一标识获取策略