KeychainUUID.m 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. //
  2. // KeychainUUID.m
  3. // keychain+uuid
  4. //
  5. // Created by aayongche on 16/2/25.
  6. // Copyright © 2016年 程磊. All rights reserved.
  7. //
  8. #import "KeychainUUID.h"
  9. #import <UIKit/UIKit.h>
  10. //导入Keychain依赖库
  11. #import <Security/Security.h>
  12. #define KEY_IN_KEYCHAIN @"app.jixincc.vip"
  13. @interface KeychainUUID ()
  14. @property (nonatomic, strong) NSString *uuid;
  15. @end
  16. @implementation KeychainUUID
  17. #pragma mark -获取UUID
  18. #pragma mark 保存UUID到钥匙串
  19. - (void)saveUDID:(NSString *)uuid
  20. {
  21. [self save:KEY_IN_KEYCHAIN data:uuid];
  22. }
  23. /**
  24. *此uuid在相同的一个程序里面-相同的vindor-相同的设备下是不会改变的
  25. *此uuid是唯一的,但应用删除再重新安装后会变化,采取的措施是:只获取一次保存在钥匙串中,之后就从钥匙串中获取
  26. **/
  27. - (NSString *)getUUID
  28. {
  29. NSString *identifierForVendor = [[UIDevice currentDevice].identifierForVendor UUIDString];
  30. return identifierForVendor;
  31. }
  32. #pragma mark 读取UUID
  33. /**
  34. *先从内存中获取uuid,如果没有再从钥匙串中获取,如果还没有就生成一个新的uuid,并保存到钥匙串中供以后使用
  35. **/
  36. - (id)readUDID
  37. {
  38. if (_uuid == nil || _uuid.length == 0) {
  39. NSString *uuidStr = (NSString *)[self load:KEY_IN_KEYCHAIN];
  40. if (uuidStr == nil || uuidStr.length == 0) {
  41. uuidStr = [self getUUID];
  42. [self saveUDID:uuidStr];
  43. }
  44. _uuid = uuidStr;
  45. }
  46. return _uuid;
  47. }
  48. #pragma mark 删除UUID
  49. - (void)deleteUUID
  50. {
  51. [self delete:KEY_IN_KEYCHAIN];
  52. }
  53. #pragma mark 查询钥匙串
  54. - (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
  55. //大家可能对这么多参数都晕了,那我就给你们一一介绍,
  56. /*
  57. kSecAttrGeneric 标识符(此属性是可选项,但是为了能获取存取的值更精确,最好还是写上吧)
  58. kSecClass 是你存数据是什么格式,这里是通用密码格式
  59. kSecAttrService 存的是什么服务,这个是用来到时候取的时候找到对应的服务存的值(这个属性类似于主键,kSecAttrService、kSecAttrAccount必须要赋一个值)
  60. kSecAttrAccount 账号,在这里作用与服务没差别(且是否必写与kSecAttrService一样)
  61. 当你有服务或者账号则必须有密码
  62. kSecAttrAccessible 安全性
  63. */
  64. return [NSMutableDictionary dictionaryWithObjectsAndKeys: (__bridge_transfer id)kSecClassGenericPassword, (__bridge_transfer id)kSecClass, @"com.chenglei",(__bridge_transfer id)kSecAttrGeneric, service, (__bridge_transfer id)kSecAttrService, service,(__bridge_transfer id)kSecAttrAccount, (__bridge_transfer id)kSecAttrAccessibleAlways,(__bridge_transfer id)kSecAttrAccessible, nil];
  65. }
  66. #pragma mark 将数据保存到钥匙串
  67. - (void)save:(NSString *)service data:(id)data {
  68. OSStatus result;
  69. NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
  70. SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
  71. [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
  72. result = SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
  73. NSCAssert( result == noErr, @"Couldn't add the Keychain Item." );
  74. }
  75. #pragma mark 更新钥匙串的数据
  76. - (void)update:(NSString *)service data:(id)data {
  77. OSStatus result;
  78. NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
  79. NSMutableDictionary *tempCheck = [self getKeychainQuery:service];
  80. [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
  81. result = SecItemUpdate((CFDictionaryRef)keychainQuery, (CFDictionaryRef)tempCheck);
  82. NSCAssert( result == noErr, @"Couldn't update the Keychain Item." );
  83. }
  84. #pragma mark 加载钥匙串中数据
  85. - (id)load:(NSString *)service {
  86. id ret = nil;
  87. NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
  88. [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];//是否要返回密码值
  89. [keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];//限制
  90. CFDataRef keyData = NULL;
  91. if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
  92. @try {
  93. ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
  94. } @catch (NSException *e) {
  95. NSLog(@"Unarchive of %@ failed: %@", service, e);
  96. } @finally {
  97. }
  98. } else {
  99. NSLog(@"Couldn't load the Keychain Item.");
  100. }
  101. return ret;
  102. }
  103. #pragma mark 删除钥匙串中数据
  104. - (void)delete:(NSString *)service {
  105. OSStatus result;
  106. NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
  107. result = SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
  108. NSCAssert( result == noErr, @"Couldn't delete the Keychain Item." );
  109. }
  110. @end