繼udid,Mac地址等一系列唯一標識無效後,如何用KeyChain來實現裝置唯一性
阿新 • • 發佈:2019-02-13
蘋果本著為使用者安全考慮的初衷導致UDID和Mac地址相繼陣亡,IMEI也不例外,為了裝置的唯一性,一代代開發者絞盡腦汁,後來KeyChain被他們瞄上了,終於可以繼續判別社別的唯一性。
原理是利用UUID,有人說,UUID是非唯一的,很容易變化,對,沒錯,但是UUID絕對不會重複對吧?所以UUID我只需要獲取一次,然後存入KeyChain,即使App被刪除了,KeyChain中的UUID也不會被刪除,如果你們公司有兩款App,完全可以通過存入的key值讀取出另一個App的UUID,做一些簡單的互動。
具體的實現方法,網上有很多種方法,很少有全套的使用方法,博主這裡重新總結了下:
先說說獲取UUID的方法:
CFUUIDRef myUUID = CFUUIDCreate( nil );
CFStringRef uuidString = CFUUIDCreateString( nil, myUUID );
NSString * result = (NSString *)CFBridgingRelease(CFStringCreateCopy( NULL, uuidString));
關於實際的儲存,都是屬於套路的程式碼了,沒什麼可讀性,直接貼出來了:
有兩個管理類:
#import <Foundation/Foundation.h>
@interface LHUUIDManager : NSObject
+(void)saveUUID; //儲存UUID
+(id)readUUID; //獲取UUID
+(void)deleteUUID; //刪除
@end
#import "LHUUIDManager.h"
#import "LHKeyChain.h"
@implementation LHUUIDManager : NSObject
static NSString * const KEY_IN_KEYCHAIN = @"KEY_IN_KEYCHAIN";
static NSString * const KEY_IN_UUID = @"KEY_IN_UUID";
+(void )saveUUID
{
NSMutableDictionary *myUUIDDic = [NSMutableDictionary dictionary];
[myUUIDDic setObject:[self creatUUID] forKey:KEY_IN_UUID];
[LHKeyChain save:KEY_IN_KEYCHAIN data:myUUIDDic];
}
+(id)readUUID
{
NSMutableDictionary *myUUIDDic = (NSMutableDictionary *)[LHKeyChain read:KEY_IN_KEYCHAIN];
return [myUUIDDic objectForKey:KEY_IN_UUID];
}
+(void)deleteUUID
{
[LHKeyChain lhDelete:KEY_IN_KEYCHAIN];
}
+(NSString *)creatUUID
{
CFUUIDRef myUUID = CFUUIDCreate( nil );
CFStringRef uuidString = CFUUIDCreateString( nil, myUUID );
NSString * result = (NSString *)CFBridgingRelease(CFStringCreateCopy( NULL, uuidString));
return result;
}
@end
#import <Foundation/Foundation.h>
@interface LHKeyChain : NSObject
+ (NSMutableDictionary *)getKeychain:(NSString *)keyChain ;
+ (void)save:(NSString *)keyChain data:(id)data;
+ (id)read:(NSString *)keyChain;
+ (void)lhDelete:(NSString *)keyChain;
@end
#import "LHKeyChain.h"
@implementation LHKeyChain
+ (NSMutableDictionary *)getKeychain:(NSString *)keyChain {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
keyChain, (__bridge_transfer id)kSecAttrService,
keyChain, (__bridge_transfer id)kSecAttrAccount,
(__bridge_transfer id)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,
nil];
}
+ (void)save:(NSString *)keyChain data:(id)data {
//Get search dictionary
NSMutableDictionary *keychainQuery = [self getKeychain:keyChain];
//Delete old item before add new item
CFDictionaryRef aRef = (__bridge_retained CFDictionaryRef)keychainQuery;
SecItemDelete(aRef);
//Add new object to search dictionary(Attention:the data format)
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
//Add item to keychain with the search dictionary
SecItemAdd(aRef, NULL);
}
+ (id)read:(NSString *)keyChain {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychain:keyChain];
//Configure the search setting
[keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];
[keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
@try {
ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
} @catch (NSException *e) {
NSLog(@"Unarchive of %@ failed: %@", keyChain, e);
} @finally {
}
}
return ret;
}
+ (void)lhDelete:(NSString *)keyChain {
NSMutableDictionary *keychainQuery = [self getKeychain:keyChain];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}
@end
到這裡是所有關鍵程式碼,放上下載地址:點選下載
最後,忘了件重要的事情,要在xcode中啟用KeyChain:
當顯示為ON的時候才能使用KeyChain。