iOS获取设备唯一标识

在开发中会遇到应用需要记录设备标示,即使应用卸载后再安装也可重新识别的情况,在这写一种实现方式——读取设备的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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值