iCloud sync keychain

后端 未结 4 828
庸人自扰
庸人自扰 2021-01-11 20:41

In my app, I want to be able to sync a configuration that gets created by the user. I wanted to use iCloud to sync that configuration so that it is always the same on all de

4条回答
  •  星月不相逢
    2021-01-11 21:32

    These are the utility methods I've made for keychain. kSecAttrSynchronizable is what makes iCloud Sync work. Hope they help.

    • Keychain Query.
    • Remove item
    • Delete item
    • Save item
    • Load item

      + (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
          return [NSMutableDictionary dictionaryWithObjectsAndKeys:
                  (__bridge id)kSecClassGenericPassword, (__bridge id)kSecClass,
                  service, (__bridge id)kSecAttrService,
                  service, (__bridge id)kSecAttrAccount,
                  service, (__bridge id)kSecAttrSynchronizable,
                  (__bridge id)kSecAttrAccessibleAfterFirstUnlock, (__bridge id)kSecAttrAccessible,
                  nil];
      }
      
      + (void)save:(NSString *)service data:(id)data {
          NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
          SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
          [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
          SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
      }
      
      + (void)remove:(NSString *)service {
           NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
           SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
      }
      
      +(NSString *)keychainItem:(NSString *)service{
          id data = [self load:service];
      
          if([data isKindOfClass:[NSString class]]){
              return data;
          }
          return @"";
      }
      
      + (id)load:(NSString *)service {
          id ret = nil;
          NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
          [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
          [keychainQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
          CFDataRef keyData = NULL;
          if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
              @try {
                  ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
              }
              @catch (NSException *e) {
                  NSLog(@"Unarchive of %@ failed: %@", service, e);
               }
              @finally {}
          }
          if (keyData) CFRelease(keyData);
          return ret;
      }
      

提交回复
热议问题