NSString+Keychain.m
6.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//
// NSString+Keychain.m
// XWTest
//
// Created by CNLive-zxw on 2019/7/8.
// Copyright © 2019 CNLive. All rights reserved.
//
#import "NSString+Keychain.h"
#import <Security/Security.h>
NSString * const CNUSER_KEY_UUID_INSTEAD = @"com.cnlive.CNLiveNetAdd.uuid";
NSString * const CNUSER_KEY_TIME_INSTEAD = @"com.cnlive.CNLiveNetAdd.time";
@implementation NSString (Keychain)
/**
* 保存已有的UUID_TS到钥匙串
*
* @param UUID UUID的字符串
* @param TS TS的字符串
*/
+ (void)xw_saveUUID:(NSString *)UUID TS:(NSString *)TS {
if (!XW_UUID_Exist || !XW_Timestamp_Exist) {
[NSString xw_save:CNUSER_KEY_UUID_INSTEAD data:UUID];
[NSString xw_save:CNUSER_KEY_TIME_INSTEAD data:TS];
}
}
/**
* @abstract 获取设备UUID
*
* 本方法是得到 UUID 后存入系统中的 keychain 的方法
* 程序删除后重装,仍可以得到相同的唯一标示
* 但是当系统刷机后,系统中的钥匙串会被清空,此时本方法失效
*
* @return 返回UUID字符串对象
*/
+ (NSString *)xw_getUUIDInKeychain {
NSString *getUDIDInKeychain = (NSString *)[NSString xw_load:CNUSER_KEY_UUID_INSTEAD];
NSLog(@"最终 ———— UUID %@",getUDIDInKeychain);
return getUDIDInKeychain;
}
+ (BOOL)xw_existUUID{
NSString *getUDIDInKeychain = (NSString *)[NSString xw_load:CNUSER_KEY_UUID_INSTEAD];
NSLog(@"从keychain中获取到的 UUID %@",getUDIDInKeychain);
if (!getUDIDInKeychain ||[getUDIDInKeychain isEqualToString:@""]||[getUDIDInKeychain isKindOfClass:[NSNull class]]) {
return NO;
}else{
return YES;
}
}
/**
* @abstract 获取时间戳
* 获取的时间戳就是第一次调用xw_getTimeInKeychain这个方法,此方法会把传入的时间戳存入系统中的 keychain
* 我们调用此方法获取时间戳的时候,如果有,则返回;如果没有,则返回当前时间戳
* 一定确保此方法在xw_getTimeInKeychain之后调用 *
*
* @return 返回时间戳字符串对象
*/
+ (NSString *)xw_getTimestampInKeychain {
NSString *getTimeInKeychain = (NSString *)[NSString xw_load:CNUSER_KEY_TIME_INSTEAD];
return getTimeInKeychain;
}
+ (BOOL)xw_existTimestamp{
NSString *getTimeInKeychain = (NSString *)[NSString xw_load:CNUSER_KEY_TIME_INSTEAD];
NSLog(@"从keychain中获取到的 UUID %@",getTimeInKeychain);
if (!getTimeInKeychain ||[getTimeInKeychain isEqualToString:@""]||[getTimeInKeychain isKindOfClass:[NSNull class]]) {
return NO;
}else{
return YES;
}
}
/**
* @abstract 获取UUID和_和时间戳3个的拼接对象
*
* 本方法一定要使用时间戳字符串调用 *
* 本方法是得到 UUID_时间戳 后存入系统中的 keychain 的方法
* 程序删除后重装,仍可以得到相同的唯一标示
* 但是当系统刷机后,系统中的钥匙串会被清空,此时本方法失效
*
* @return 返回获取UUID和_和时间戳3个的拼接对象
*/
- (NSString *)xw_getUUIDTimestampInKeychain {
NSString *getUDIDInKeychain = (NSString *)[NSString xw_load:CNUSER_KEY_UUID_INSTEAD];
NSLog(@"从keychain中获取到的 UUID %@",getUDIDInKeychain);
if (!getUDIDInKeychain ||[getUDIDInKeychain isEqualToString:@""]||[getUDIDInKeychain isKindOfClass:[NSNull class]]) {
CFUUIDRef puuid = CFUUIDCreate( nil );
CFStringRef uuidString = CFUUIDCreateString( nil, puuid );
NSString * idfv = (NSString *)CFBridgingRelease(CFStringCreateCopy( NULL, uuidString));
NSString *result = [idfv stringByReplacingOccurrencesOfString:@"-" withString:@""];
CFRelease(puuid);
CFRelease(uuidString);
NSLog(@"\n \n \n _____重新存储 UUID_____\n \n \n %@",result);
[NSString xw_save:CNUSER_KEY_UUID_INSTEAD data:result];
getUDIDInKeychain = (NSString *)[NSString xw_load:CNUSER_KEY_UUID_INSTEAD];
}
NSString *getTimeInKeychain = (NSString *)[NSString xw_load:CNUSER_KEY_TIME_INSTEAD];
if (!getTimeInKeychain ||[getTimeInKeychain isEqualToString:@""]||[getTimeInKeychain isKindOfClass:[NSNull class]]) {
[NSString xw_save:CNUSER_KEY_TIME_INSTEAD data:self];
getTimeInKeychain = (NSString *)[NSString xw_load:CNUSER_KEY_TIME_INSTEAD];
}
NSString *string = [NSString stringWithFormat:@"%@_%@",getUDIDInKeychain,getTimeInKeychain];
NSLog(@"最终 ———— UUID_时间戳 %@",string);
return string;
}
//保存数据至钥匙串中
+ (void)xw_save:(NSString *)service data:(id)data {
//Get search dictionary
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
//Delete old item before add new item
SecItemDelete((CFDictionaryRef)keychainQuery);
//Add new object to search dictionary(Attention:the data format)
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData];
//Add item to keychain with the search dictionary
SecItemAdd((CFDictionaryRef)keychainQuery, NULL);
}
//从钥匙串中加载数据
+ (id)xw_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:(id)kSecReturnData];
[keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((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;
}
//删除数据
+ (void)xw_delete:(NSString *)service {
NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
SecItemDelete((CFDictionaryRef)keychainQuery);
}
//通过 key 获取数据
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(id)kSecClassGenericPassword,(id)kSecClass,
service, (id)kSecAttrService,
service, (id)kSecAttrAccount,
(id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible,
nil];
}
+ (void)xw_deletes{
[NSString xw_delete:CNUSER_KEY_UUID_INSTEAD];
[NSString xw_delete:CNUSER_KEY_TIME_INSTEAD];
}
@end