随着苹果爸爸的不断改革,现在想获取一台手机的唯一标示是难上加难,但是办法还是有的,下面就来介绍一下最简单安全的办法,获取手机唯一标示。(首先说明这种方法的弊端,手机系统升级后这个唯一的ID也会变化)
以前废弃的方法就不一一细说了,直接说笔者是怎么做的吧
- 采用Keychain+[[NSUUID UUID] UUIDString] 的方法
开发者可以在应用第一次启动时仅仅调用一次,然后利用Keychain将该串存储起来,如果Keychain存储了UUID就不需要再存储了。如果用户删除该应用再次安装时,Keychain存储的UUID也不会消失,所以能保证唯一识别该设备。
-
keychain介绍
iOS的keychain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keychain存储。相对于NSUserDefaults、文件保存等一般方式,keychain保存更为安全,而且keychain里保存的信息不会因App被删除而丢失,所以在重装App后,keychain里的数据还能使用。 -
keychain代码
#import <Foundation/Foundation.h>
#import <Security/Security.h>
NS_ASSUME_NONNULL_BEGIN
@interface ZXXKeyChain : NSObject
/**
添加keyChain数据
@param data s数据
@param key key值
*/
+ (void)addKeychainData:(id)data forKey:(NSString *)key;
/**
根据key值获取数据
@param key key值
@return 返回数据
*/
+ (id)getKeychainDataForKey:(NSString *)key;
/**
根据key值删除数据
@param key key值
*/
+ (void)deleteKeychainDataForKey:(NSString *)key;
@end
NS_ASSUME_NONNULL_END
#import "ZXXKeyChain.h"
@implementation ZXXKeyChain
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
return [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kSecClassGenericPassword,(id)kSecClass,// 标识符(kSecAttrGeneric通常值位密码)
service, (__bridge id)kSecAttrService,// 服务(kSecAttrService)
service, (__bridge id)kSecAttrAccount,// 账户(kSecAttrAccount)
(__bridge id)kSecAttrAccessibleAfterFirstUnlock,(__bridge id)kSecAttrAccessible,// kSecAttrAccessiblein变量用来指定这个应用何时需要访问这个数据
nil];
}
+ (void)addKeychainData:(id)data forKey:(NSString *)key {
// 获取查询字典
NSMutableDictionary *keychainQuery = [self getKeychainQuery:key];
// 在添加之前先删除旧数据
SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
// 添加新的数据到字典
[keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
// 将数据字典添加到钥匙串
SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
}
+ (id)getKeychainDataForKey:(NSString *)key {
id ret = nil;
NSMutableDictionary *keychainQuery = [self getKeychainQuery: key];
[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: %@", key, e);
} @finally {
}
}
return ret;
}
+ (void)deleteKeychainDataForKey:(NSString *)key {
NSMutableDictionary *keychainQuery = [self getKeychainQuery: key];
SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}
- 具体实现在AppDelegate实现以下代码
- (void)creatOnlyID{
NSString *uuidStr = [[NSUUID UUID] UUIDString];
NSString *getStr = [ZXXKeyChain getKeychainDataForKey:@"UUID"];
if (getStr.length == 0) {
[ZXXKeyChain addKeychainData:uuidStr forKey:@"UUID"];
}
}
这种方法还是存在问题,当手机系统升级后,KeyChain中存储的值会变化,现在还没有好的对策,欢迎大神@指正
网友评论