iOS keyChain 钥匙串

2019-08-21  本文已影响0人  邓立_全栈UncleLi

今天刚好需要把东西存到钥匙串(keyChain)中,本项目是oc的,那就用oc实现这个鬼东西...
首先把四个文件复制进去
文件一:

//
//  SAMKeychain.h
//  SAMKeychain
//
//

#if __has_feature(modules)
@import Foundation;
#else
#import <Foundation/Foundation.h>
#endif

NS_ASSUME_NONNULL_BEGIN

/**
 Error code specific to SAMKeychain that can be returned in NSError objects.
 For codes returned by the operating system, refer to SecBase.h for your
 platform.
 */
typedef NS_ENUM(OSStatus, SAMKeychainErrorCode) {
  /** Some of the arguments were invalid. */
  SAMKeychainErrorBadArguments = -1001,
};

/** SAMKeychain error domain */
extern NSString *const kSAMKeychainErrorDomain;

/** Account name. */
extern NSString *const kSAMKeychainAccountKey;

/**
 Time the item was created.
 
 The value will be a string.
 */
extern NSString *const kSAMKeychainCreatedAtKey;

/** Item class. */
extern NSString *const kSAMKeychainClassKey;

/** Item description. */
extern NSString *const kSAMKeychainDescriptionKey;

/** Item label. */
extern NSString *const kSAMKeychainLabelKey;

/** Time the item was last modified.
 
 The value will be a string.
 */
extern NSString *const kSAMKeychainLastModifiedKey;

/** Where the item was created. */
extern NSString *const kSAMKeychainWhereKey;

/**
 Simple wrapper for accessing accounts, getting passwords, setting passwords, and deleting passwords using the system
 Keychain on Mac OS X and iOS.
 
 This was originally inspired by EMKeychain and SDKeychain (both of which are now gone). Thanks to the authors.
 SAMKeychain has since switched to a simpler implementation that was abstracted from [SSToolkit](http://sstoolk.it).
 */
@interface SAMKeychain : NSObject

#pragma mark - Classic methods

/**
 Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't have a
 password for the given parameters.
 
 @param serviceName The service for which to return the corresponding password.
 
 @param account The account for which to return the corresponding password.
 
 @return Returns a string containing the password for a given account and service, or `nil` if the Keychain doesn't
 have a password for the given parameters.
 */
+ (nullable NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account;
+ (nullable NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error __attribute__((swift_error(none)));

/**
 Returns a nsdata containing the password for a given account and service, or `nil` if the Keychain doesn't have a
 password for the given parameters.
 
 @param serviceName The service for which to return the corresponding password.
 
 @param account The account for which to return the corresponding password.
 
 @return Returns a nsdata containing the password for a given account and service, or `nil` if the Keychain doesn't
 have a password for the given parameters.
 */
+ (nullable NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account;
+ (nullable NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error __attribute__((swift_error(none)));


/**
 Deletes a password from the Keychain.
 
 @param serviceName The service for which to delete the corresponding password.
 
 @param account The account for which to delete the corresponding password.
 
 @return Returns `YES` on success, or `NO` on failure.
 */
+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account;
+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error __attribute__((swift_error(none)));


/**
 Sets a password in the Keychain.
 
 @param password The password to store in the Keychain.
 
 @param serviceName The service for which to set the corresponding password.
 
 @param account The account for which to set the corresponding password.
 
 @return Returns `YES` on success, or `NO` on failure.
 */
+ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account;
+ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error __attribute__((swift_error(none)));

/**
 Sets a password in the Keychain.
 
 @param password The password to store in the Keychain.
 
 @param serviceName The service for which to set the corresponding password.
 
 @param account The account for which to set the corresponding password.
 
 @return Returns `YES` on success, or `NO` on failure.
 */
+ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account;
+ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error __attribute__((swift_error(none)));

/**
 Returns an array containing the Keychain's accounts, or `nil` if the Keychain has no accounts.
 
 See the `NSString` constants declared in SAMKeychain.h for a list of keys that can be used when accessing the
 dictionaries returned by this method.
 
 @return An array of dictionaries containing the Keychain's accounts, or `nil` if the Keychain doesn't have any
 accounts. The order of the objects in the array isn't defined.
 */
+ (nullable NSArray<NSDictionary<NSString *, id> *> *)allAccounts;
+ (nullable NSArray<NSDictionary<NSString *, id> *> *)allAccounts:(NSError *__autoreleasing *)error __attribute__((swift_error(none)));


/**
 Returns an array containing the Keychain's accounts for a given service, or `nil` if the Keychain doesn't have any
 accounts for the given service.
 
 See the `NSString` constants declared in SAMKeychain.h for a list of keys that can be used when accessing the
 dictionaries returned by this method.
 
 @param serviceName The service for which to return the corresponding accounts.
 
 @return An array of dictionaries containing the Keychain's accounts for a given `serviceName`, or `nil` if the Keychain
 doesn't have any accounts for the given `serviceName`. The order of the objects in the array isn't defined.
 */
+ (nullable NSArray<NSDictionary<NSString *, id> *> *)accountsForService:(nullable NSString *)serviceName;
+ (nullable NSArray<NSDictionary<NSString *, id> *> *)accountsForService:(nullable NSString *)serviceName error:(NSError *__autoreleasing *)error __attribute__((swift_error(none)));


#pragma mark - Configuration

#if __IPHONE_4_0 && TARGET_OS_IPHONE
/**
 Returns the accessibility type for all future passwords saved to the Keychain.
 
 @return Returns the accessibility type.
 
 The return value will be `NULL` or one of the "Keychain Item Accessibility
 Constants" used for determining when a keychain item should be readable.
 
 @see setAccessibilityType
 */
+ (CFTypeRef)accessibilityType;

/**
 Sets the accessibility type for all future passwords saved to the Keychain.
 
 @param accessibilityType One of the "Keychain Item Accessibility Constants"
 used for determining when a keychain item should be readable.
 
 If the value is `NULL` (the default), the Keychain default will be used which
 is highly insecure. You really should use at least `kSecAttrAccessibleAfterFirstUnlock`
 for background applications or `kSecAttrAccessibleWhenUnlocked` for all
 other applications.
 
 @see accessibilityType
 */
+ (void)setAccessibilityType:(CFTypeRef)accessibilityType;
#endif

@end

NS_ASSUME_NONNULL_END

#import "SAMKeychainQuery.h"

文件二:

//
//  SAMKeychain.m
//  SAMKeychain
//
//

#import "SAMKeychain.h"
#import "SAMKeychainQuery.h"

NSString *const kSAMKeychainErrorDomain = @"com.samsoffes.samkeychain";
NSString *const kSAMKeychainAccountKey = @"acct";
NSString *const kSAMKeychainCreatedAtKey = @"cdat";
NSString *const kSAMKeychainClassKey = @"labl";
NSString *const kSAMKeychainDescriptionKey = @"desc";
NSString *const kSAMKeychainLabelKey = @"labl";
NSString *const kSAMKeychainLastModifiedKey = @"mdat";
NSString *const kSAMKeychainWhereKey = @"svce";

#if __IPHONE_4_0 && TARGET_OS_IPHONE
static CFTypeRef SAMKeychainAccessibilityType = NULL;
#endif

@implementation SAMKeychain

+ (nullable NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account {
  return [self passwordForService:serviceName account:account error:nil];
}


+ (nullable NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account error:(NSError *__autoreleasing *)error {
  SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init];
  query.service = serviceName;
  query.account = account;
  [query fetch:error];
  return query.password;
}

+ (nullable NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account {
  return [self passwordDataForService:serviceName account:account error:nil];
}

+ (nullable NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error {
  SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init];
  query.service = serviceName;
  query.account = account;
  [query fetch:error];
  
  return query.passwordData;
}


+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account {
  return [self deletePasswordForService:serviceName account:account error:nil];
}


+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account error:(NSError *__autoreleasing *)error {
  SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init];
  query.service = serviceName;
  query.account = account;
  return [query deleteItem:error];
}


+ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account {
  return [self setPassword:password forService:serviceName account:account error:nil];
}


+ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError *__autoreleasing *)error {
  SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init];
  query.service = serviceName;
  query.account = account;
  query.password = password;
  return [query save:error];
}

+ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account {
  return [self setPasswordData:password forService:serviceName account:account error:nil];
}


+ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error {
  SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init];
  query.service = serviceName;
  query.account = account;
  query.passwordData = password;
  return [query save:error];
}

+ (nullable NSArray *)allAccounts {
  return [self allAccounts:nil];
}


+ (nullable NSArray *)allAccounts:(NSError *__autoreleasing *)error {
  return [self accountsForService:nil error:error];
}


+ (nullable NSArray *)accountsForService:(nullable NSString *)serviceName {
  return [self accountsForService:serviceName error:nil];
}


+ (nullable NSArray *)accountsForService:(nullable NSString *)serviceName error:(NSError *__autoreleasing *)error {
  SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init];
  query.service = serviceName;
  return [query fetchAll:error];
}


#if __IPHONE_4_0 && TARGET_OS_IPHONE
+ (CFTypeRef)accessibilityType {
  return SAMKeychainAccessibilityType;
}


+ (void)setAccessibilityType:(CFTypeRef)accessibilityType {
  CFRetain(accessibilityType);
  if (SAMKeychainAccessibilityType) {
    CFRelease(SAMKeychainAccessibilityType);
  }
  SAMKeychainAccessibilityType = accessibilityType;
}
#endif

@end

文件三:

//
//  SAMKeychainQuery.h
//  SAMKeychain
//
//

#if __has_feature(modules)
@import Foundation;
@import Security;
#else
#import <Foundation/Foundation.h>
#import <Security/Security.h>
#endif

NS_ASSUME_NONNULL_BEGIN

#if __IPHONE_7_0 || __MAC_10_9
// Keychain synchronization available at compile time
#define SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE 1
#endif

#if __IPHONE_3_0 || __MAC_10_9
// Keychain access group available at compile time
#define SAMKEYCHAIN_ACCESS_GROUP_AVAILABLE 1
#endif

#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE
typedef NS_ENUM(NSUInteger, SAMKeychainQuerySynchronizationMode) {
  SAMKeychainQuerySynchronizationModeAny,
  SAMKeychainQuerySynchronizationModeNo,
  SAMKeychainQuerySynchronizationModeYes
};
#endif

/**
 Simple interface for querying or modifying keychain items.
 */
@interface SAMKeychainQuery : NSObject

/** kSecAttrAccount */
@property (nonatomic, copy, nullable) NSString *account;

/** kSecAttrService */
@property (nonatomic, copy, nullable) NSString *service;

/** kSecAttrLabel */
@property (nonatomic, copy, nullable) NSString *label;

#ifdef SAMKEYCHAIN_ACCESS_GROUP_AVAILABLE
/** kSecAttrAccessGroup (only used on iOS) */
@property (nonatomic, copy, nullable) NSString *accessGroup;
#endif

#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE
/** kSecAttrSynchronizable */
@property (nonatomic) SAMKeychainQuerySynchronizationMode synchronizationMode;
#endif

/** Root storage for password information */
@property (nonatomic, copy, nullable) NSData *passwordData;

/**
 This property automatically transitions between an object and the value of
 `passwordData` using NSKeyedArchiver and NSKeyedUnarchiver.
 */
@property (nonatomic, copy, nullable) id<NSCoding> passwordObject;

/**
 Convenience accessor for setting and getting a password string. Passes through
 to `passwordData` using UTF-8 string encoding.
 */
@property (nonatomic, copy, nullable) NSString *password;


///------------------------
/// @name Saving & Deleting
///------------------------

/**
 Save the receiver's attributes as a keychain item. Existing items with the
 given account, service, and access group will first be deleted.
 
 @param error Populated should an error occur.
 
 @return `YES` if saving was successful, `NO` otherwise.
 */
- (BOOL)save:(NSError **)error;

/**
 Delete keychain items that match the given account, service, and access group.
 
 @param error Populated should an error occur.
 
 @return `YES` if saving was successful, `NO` otherwise.
 */
- (BOOL)deleteItem:(NSError **)error;


///---------------
/// @name Fetching
///---------------

/**
 Fetch all keychain items that match the given account, service, and access
 group. The values of `password` and `passwordData` are ignored when fetching.
 
 @param error Populated should an error occur.
 
 @return An array of dictionaries that represent all matching keychain items or
 `nil` should an error occur.
 The order of the items is not determined.
 */
- (nullable NSArray<NSDictionary<NSString *, id> *> *)fetchAll:(NSError **)error;

/**
 Fetch the keychain item that matches the given account, service, and access
 group. The `password` and `passwordData` properties will be populated unless
 an error occurs. The values of `password` and `passwordData` are ignored when
 fetching.
 
 @param error Populated should an error occur.
 
 @return `YES` if fetching was successful, `NO` otherwise.
 */
- (BOOL)fetch:(NSError **)error;


///-----------------------------
/// @name Synchronization Status
///-----------------------------

#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE
/**
 Returns a boolean indicating if keychain synchronization is available on the device at runtime. The #define
 SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE is only for compile time. If you are checking for the presence of synchronization,
 you should use this method.
 
 @return A value indicating if keychain synchronization is available
 */
+ (BOOL)isSynchronizationAvailable;
#endif

@end

NS_ASSUME_NONNULL_END

文件四:

//
//  SAMKeychainQuery.m
//  SAMKeychain
//
//

#import "SAMKeychainQuery.h"
#import "SAMKeychain.h"

@implementation SAMKeychainQuery

@synthesize account = _account;
@synthesize service = _service;
@synthesize label = _label;
@synthesize passwordData = _passwordData;

#ifdef SAMKEYCHAIN_ACCESS_GROUP_AVAILABLE
@synthesize accessGroup = _accessGroup;
#endif

#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE
@synthesize synchronizationMode = _synchronizationMode;
#endif

#pragma mark - Public

- (BOOL)save:(NSError *__autoreleasing *)error {
  OSStatus status = SAMKeychainErrorBadArguments;
  if (!self.service || !self.account || !self.passwordData) {
    if (error) {
      *error = [[self class] errorWithCode:status];
    }
    return NO;
  }
  NSMutableDictionary *query = nil;
  NSMutableDictionary * searchQuery = [self query];
  status = SecItemCopyMatching((__bridge CFDictionaryRef)searchQuery, nil);
  if (status == errSecSuccess) {//item already exists, update it!
    query = [[NSMutableDictionary alloc]init];
    [query setObject:self.passwordData forKey:(__bridge id)kSecValueData];
#if __IPHONE_4_0 && TARGET_OS_IPHONE
    CFTypeRef accessibilityType = [SAMKeychain accessibilityType];
    if (accessibilityType) {
      [query setObject:(__bridge id)accessibilityType forKey:(__bridge id)kSecAttrAccessible];
    }
#endif
    status = SecItemUpdate((__bridge CFDictionaryRef)(searchQuery), (__bridge CFDictionaryRef)(query));
  }else if(status == errSecItemNotFound){//item not found, create it!
    query = [self query];
    if (self.label) {
      [query setObject:self.label forKey:(__bridge id)kSecAttrLabel];
    }
    [query setObject:self.passwordData forKey:(__bridge id)kSecValueData];
#if __IPHONE_4_0 && TARGET_OS_IPHONE
    CFTypeRef accessibilityType = [SAMKeychain accessibilityType];
    if (accessibilityType) {
      [query setObject:(__bridge id)accessibilityType forKey:(__bridge id)kSecAttrAccessible];
    }
#endif
    status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
  }
  if (status != errSecSuccess && error != NULL) {
    *error = [[self class] errorWithCode:status];
  }
  return (status == errSecSuccess);}


- (BOOL)deleteItem:(NSError *__autoreleasing *)error {
  OSStatus status = SAMKeychainErrorBadArguments;
  if (!self.service || !self.account) {
    if (error) {
      *error = [[self class] errorWithCode:status];
    }
    return NO;
  }
  
  NSMutableDictionary *query = [self query];
#if TARGET_OS_IPHONE
  status = SecItemDelete((__bridge CFDictionaryRef)query);
#else
  // On Mac OS, SecItemDelete will not delete a key created in a different
  // app, nor in a different version of the same app.
  //
  // To replicate the issue, save a password, change to the code and
  // rebuild the app, and then attempt to delete that password.
  //
  // This was true in OS X 10.6 and probably later versions as well.
  //
  // Work around it by using SecItemCopyMatching and SecKeychainItemDelete.
  CFTypeRef result = NULL;
  [query setObject:@YES forKey:(__bridge id)kSecReturnRef];
  status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
  if (status == errSecSuccess) {
    status = SecKeychainItemDelete((SecKeychainItemRef)result);
    CFRelease(result);
  }
#endif
  
  if (status != errSecSuccess && error != NULL) {
    *error = [[self class] errorWithCode:status];
  }
  
  return (status == errSecSuccess);
}


- (nullable NSArray *)fetchAll:(NSError *__autoreleasing *)error {
  NSMutableDictionary *query = [self query];
  [query setObject:@YES forKey:(__bridge id)kSecReturnAttributes];
  [query setObject:(__bridge id)kSecMatchLimitAll forKey:(__bridge id)kSecMatchLimit];
#if __IPHONE_4_0 && TARGET_OS_IPHONE
  CFTypeRef accessibilityType = [SAMKeychain accessibilityType];
  if (accessibilityType) {
    [query setObject:(__bridge id)accessibilityType forKey:(__bridge id)kSecAttrAccessible];
  }
#endif
  
  CFTypeRef result = NULL;
  OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
  if (status != errSecSuccess && error != NULL) {
    *error = [[self class] errorWithCode:status];
    return nil;
  }
  
  return (__bridge_transfer NSArray *)result;
}


- (BOOL)fetch:(NSError *__autoreleasing *)error {
  OSStatus status = SAMKeychainErrorBadArguments;
  if (!self.service || !self.account) {
    if (error) {
      *error = [[self class] errorWithCode:status];
    }
    return NO;
  }
  
  CFTypeRef result = NULL;
  NSMutableDictionary *query = [self query];
  [query setObject:@YES forKey:(__bridge id)kSecReturnData];
  [query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
  status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
  
  if (status != errSecSuccess) {
    if (error) {
      *error = [[self class] errorWithCode:status];
    }
    return NO;
  }
  
  self.passwordData = (__bridge_transfer NSData *)result;
  return YES;
}


#pragma mark - Accessors

- (void)setPasswordObject:(id<NSCoding>)object {
  self.passwordData = [NSKeyedArchiver archivedDataWithRootObject:object];
}


- (id<NSCoding>)passwordObject {
  if ([self.passwordData length]) {
    return [NSKeyedUnarchiver unarchiveObjectWithData:self.passwordData];
  }
  return nil;
}


- (void)setPassword:(NSString *)password {
  self.passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
}


- (NSString *)password {
  if ([self.passwordData length]) {
    return [[NSString alloc] initWithData:self.passwordData encoding:NSUTF8StringEncoding];
  }
  return nil;
}


#pragma mark - Synchronization Status

#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE
+ (BOOL)isSynchronizationAvailable {
#if TARGET_OS_IPHONE
  // Apple suggested way to check for 7.0 at runtime
  // https://developer.apple.com/library/ios/documentation/userexperience/conceptual/transitionguide/SupportingEarlieriOS.html
  return floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1;
#else
  return floor(NSFoundationVersionNumber) > NSFoundationVersionNumber10_8_4;
#endif
}
#endif


#pragma mark - Private

- (NSMutableDictionary *)query {
  NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:3];
  [dictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
  
  if (self.service) {
    [dictionary setObject:self.service forKey:(__bridge id)kSecAttrService];
  }
  
  if (self.account) {
    [dictionary setObject:self.account forKey:(__bridge id)kSecAttrAccount];
  }
  
#ifdef SAMKEYCHAIN_ACCESS_GROUP_AVAILABLE
#if !TARGET_IPHONE_SIMULATOR
  if (self.accessGroup) {
    [dictionary setObject:self.accessGroup forKey:(__bridge id)kSecAttrAccessGroup];
  }
#endif
#endif
  
#ifdef SAMKEYCHAIN_SYNCHRONIZATION_AVAILABLE
  if ([[self class] isSynchronizationAvailable]) {
    id value;
    
    switch (self.synchronizationMode) {
      case SAMKeychainQuerySynchronizationModeNo: {
        value = @NO;
        break;
      }
      case SAMKeychainQuerySynchronizationModeYes: {
        value = @YES;
        break;
      }
      case SAMKeychainQuerySynchronizationModeAny: {
        value = (__bridge id)(kSecAttrSynchronizableAny);
        break;
      }
    }
    
    [dictionary setObject:value forKey:(__bridge id)(kSecAttrSynchronizable)];
  }
#endif
  
  return dictionary;
}


+ (NSError *)errorWithCode:(OSStatus) code {
  static dispatch_once_t onceToken;
  static NSBundle *resourcesBundle = nil;
  dispatch_once(&onceToken, ^{
    NSURL *url = [[NSBundle bundleForClass:[SAMKeychainQuery class]] URLForResource:@"SAMKeychain" withExtension:@"bundle"];
    resourcesBundle = [NSBundle bundleWithURL:url];
  });
  
  NSString *message = nil;
  switch (code) {
    case errSecSuccess: return nil;
    case SAMKeychainErrorBadArguments: message = NSLocalizedStringFromTableInBundle(@"SAMKeychainErrorBadArguments", @"SAMKeychain", resourcesBundle, nil); break;
      
#if TARGET_OS_IPHONE
    case errSecUnimplemented: {
      message = NSLocalizedStringFromTableInBundle(@"errSecUnimplemented", @"SAMKeychain", resourcesBundle, nil);
      break;
    }
    case errSecParam: {
      message = NSLocalizedStringFromTableInBundle(@"errSecParam", @"SAMKeychain", resourcesBundle, nil);
      break;
    }
    case errSecAllocate: {
      message = NSLocalizedStringFromTableInBundle(@"errSecAllocate", @"SAMKeychain", resourcesBundle, nil);
      break;
    }
    case errSecNotAvailable: {
      message = NSLocalizedStringFromTableInBundle(@"errSecNotAvailable", @"SAMKeychain", resourcesBundle, nil);
      break;
    }
    case errSecDuplicateItem: {
      message = NSLocalizedStringFromTableInBundle(@"errSecDuplicateItem", @"SAMKeychain", resourcesBundle, nil);
      break;
    }
    case errSecItemNotFound: {
      message = NSLocalizedStringFromTableInBundle(@"errSecItemNotFound", @"SAMKeychain", resourcesBundle, nil);
      break;
    }
    case errSecInteractionNotAllowed: {
      message = NSLocalizedStringFromTableInBundle(@"errSecInteractionNotAllowed", @"SAMKeychain", resourcesBundle, nil);
      break;
    }
    case errSecDecode: {
      message = NSLocalizedStringFromTableInBundle(@"errSecDecode", @"SAMKeychain", resourcesBundle, nil);
      break;
    }
    case errSecAuthFailed: {
      message = NSLocalizedStringFromTableInBundle(@"errSecAuthFailed", @"SAMKeychain", resourcesBundle, nil);
      break;
    }
    default: {
      message = NSLocalizedStringFromTableInBundle(@"errSecDefault", @"SAMKeychain", resourcesBundle, nil);
    }
#else
    default:
      message = (__bridge_transfer NSString *)SecCopyErrorMessageString(code, NULL);
#endif
  }
  
  NSDictionary *userInfo = nil;
  if (message) {
    userInfo = @{ NSLocalizedDescriptionKey : message };
  }
  return [NSError errorWithDomain:kSAMKeychainErrorDomain code:code userInfo:userInfo];
}

@end

最后调用,我这里是取idfa的值存到(keyChain)钥匙串中,要是idfa取不到,就把idfv存到(keyChain)钥匙串中,代码如下
第一步:

#import "SAMKeychain.h"
#import "SAMKeychainQuery.h"

第二步:

  NSString *forService = @"com.test-yqj.www";
  NSString *forAccount = @"deviceUid";
  
  NSError *passwordForServiceError = nil;
  NSError *setPasswordError = nil;
  
  NSString *passwordForService = [SAMKeychain passwordForService: forService account: forAccount error: &passwordForServiceError];
  
  NSString *deviceUid = @"";
  NSString *defaultType = @"";
  if (passwordForService == nil) {
    
    // idfa 00000000-0000-0000-0000-000000000000
    NSString *idfa = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
    NSString *defaultIdfa = @"00000000-0000-0000-0000-000000000000";
    if ([defaultIdfa isEqualToString:idfa]) {
      //idfv
      NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
      deviceUid = idfv;
      defaultType = @"idfv";
    } else{
      deviceUid = idfa;
      defaultType = @"idfa";
    }
    
    [SAMKeychain setPassword: deviceUid forService: forService account: forAccount error: &setPasswordError];
    
  } else {
    deviceUid = passwordForService;
    defaultType = @"keyChain";
  }

上图中注释的00000000-0000-0000-0000-000000000000是当idfa取不到的时候系统返回的默认字符串类型初始值,当然还可以更简化,主要看业务需求

下面是四个文件的方法介绍

+ (NSArray *)allAccounts; //获取所有账户
+ (NSArray *)accountsForService:(NSString *)serviceName; //获取所有服务名
+ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account; //获取对应服务名的账户
+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account; //删除对应服务名的账户的密码
+ (void)setAccessibilityType:(CFTypeRef)accessibilityType; //设置类型
+ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account; //设置对应服务名的账户的密码

调试方法

NSError *error = nil;
SAMKeychainQuery *query = [[SAMKeychainQuery alloc] init];
query.service = @"MyService";
query.account = @"soffes";
[query fetch:&error];

if ([error code] == errSecItemNotFound) {
    NSLog(@"Password not found");
} else if (error != nil) {
    NSLog(@"Some other error occurred: %@", [error localizedDescription]);
}

okay,结束,剩余时间去看动作大片吧哈

上一篇下一篇

猜你喜欢

热点阅读