OC(廿二)-识别-iOS-设备的唯一性策略--UUID keyChain存储 - 图1

    iOS的keyChain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keyChain存储。相对于NSUserDefaults、文件保存等一般方式,keyChain保存更为安全,而且keyChain里保存的信息不会因App被删除而丢失,所以在重装App后,keychain里的数据还能使用,只有刷机或者越狱才对其中的数据有影响.

    思路如下:
    1,安装 APP 后自动生成一个 UUID
    2,检查keyChain中是否有相应关键字的 UUID,如果没有存储,反之不存储.
    3,keychain里的数据还能使用,只有刷机或者越狱才对其中的数据有影响.
    所以可以很有效保证设备唯一性需求.

    代码如下:(封装 keyChain 的方法)
    . h

    1. //
    2. // KeyChainManager.h
    3. // ChartDemo
    4. //
    5. // Created by user on 2017/9/27.
    6. // Copyright © 2017年 MK. All rights reserved.
    7. //
    8. #import <Foundation/Foundation.h>
    9. @interface KeyChainManager : NSObject
    10. + (NSString *)isExistUUID;
    11. /**
    12. 添加 UUID
    13. @param uuid 添加的对象
    14. */
    15. + (void ) addObject:(NSString *)uuid ;
    16. /**
    17. 删除 UUID
    18. */
    19. + (void ) removeObject;
    20. @end

    .m

    1. //
    2. // KeyChainManager.m
    3. // ChartDemo
    4. //
    5. // Created by user on 2017/9/27.
    6. // Copyright © 2017年 MK. All rights reserved.
    7. //
    8. #import "KeyChainManager.h"
    9. #import <Security/Security.h>
    10. @implementation KeyChainManager
    11. static NSString * const MY_UUIDDictionaryKEY = @"com.MK.ChartDemo";
    12. static NSString * const MY_UUIDKEY = @"com.MK.ChartDemoKey";
    13. + (NSString *)isExistUUID{
    14. NSString * uuid = (NSString *)[self showUUID];
    15. NSLog(@"UUid : %@", uuid);
    16. return uuid;
    17. }
    18. + (void) addObject:(NSString *)uuid{
    19. if (uuid) {
    20. NSMutableDictionary * dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:uuid,MY_UUIDDictionaryKEY, nil];
    21. NSMutableDictionary * query = [self getKeyChainQuery:MY_UUIDKEY];
    22. if (query) {
    23. SecItemDelete((CFDictionaryRef)query);
    24. [query setObject:[NSKeyedArchiver archivedDataWithRootObject:dict] forKey:(id)kSecValueData];
    25. SecItemAdd((CFDictionaryRef)query, NULL);
    26. }
    27. }
    28. }
    29. + (void)removeObject{
    30. SecItemDelete((CFDictionaryRef)[self getKeyChainQuery:MY_UUIDKEY]);
    31. }
    32. + (id)showUUID{
    33. id selectObject = nil;
    34. NSMutableDictionary * query = [self getKeyChainQuery:MY_UUIDKEY];
    35. [query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
    36. [query setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
    37. CFDataRef data = NULL;
    38. if (SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&data) == noErr) {
    39. @try{
    40. selectObject = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)data];
    41. }@catch (NSException * e){
    42. NSLog(@"解包异常 %@ : %@", query, e);
    43. }@finally{
    44. }
    45. }
    46. if (data) {
    47. CFRelease(data);
    48. }
    49. if (selectObject) {
    50. return [((NSDictionary *)selectObject) objectForKey:MY_UUIDDictionaryKEY];
    51. }
    52. return nil;
    53. }
    54. /**
    55. 获取KeyChain的查询
    56. @param key 关键字
    57. @return 获得查询的 ref
    58. */
    59. + (NSMutableDictionary *) getKeyChainQuery:(NSString *) key{
    60. return [NSMutableDictionary dictionaryWithObjectsAndKeys:(id)kSecClassGenericPassword,(id)kSecClass,key, (id)kSecAttrService,key, (id)kSecAttrAccount,(id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,nil];
    61. }
    62. @end

    AppDelegate中的调用:

    1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    2. // Override point for customization after application launch.
    3. if (![KeyChainManager isExistUUID]) {
    4. [KeyChainManager addObject:[[NSUUID UUID] UUIDString]];
    5. }
    6. return YES;
    7. }