您的位置:首页 > 移动开发 > IOS开发

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息