美文网首页
iOS keyChain 钥匙串

iOS keyChain 钥匙串

作者: 邓立_全栈UncleLi | 来源:发表于2019-08-21 05:28 被阅读0次

    今天刚好需要把东西存到钥匙串(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,结束,剩余时间去看动作大片吧哈

    相关文章

      网友评论

          本文标题:iOS keyChain 钥匙串

          本文链接:https://www.haomeiwen.com/subject/uwevsctx.html