zoukankan      html  css  js  c++  java
  • KeyChainWrapper

    1 keyChainWrapper是MRC代码,要禁用ARC -fno-objc-arc

    2 要导入Security.framework框架

    3 获得一个不变的UUID

     1 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
     2     // 判断Keychain中是否存在这条Item如果不存在SecItem就添加。
     3     NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
     4                            (__bridge NSString *)kSecClassGenericPassword, kSecClass,
     5                            @"bundleSeedID", kSecAttrAccount,
     6                            @"", kSecAttrService,
                      //设置为True可以配合SecItemCopyMatching属性获得SecItem的信息。有的话
    7 (id)kCFBooleanTrue, kSecReturnAttributes, 8 nil]; 9 CFDictionaryRef result = nil; 10 OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&result); 11 if (status == errSecItemNotFound) 12 status = SecItemAdd((CFDictionaryRef)query, (CFTypeRef *)&result); 13 if (status != errSecSuccess) 14 return nil; 15 // 获取AccessGroup即 AppIdentifierPrefix 和 Bundle Id的组合。 16 NSString *accessGroup = [(__bridge NSDictionary *)result objectForKey:(__bridge NSString *)kSecAttrAccessGroup]; 17 // 初始化(根据标识符获取)一个wrapper 18 KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"jifeifei" accessGroup:accessGroup]; 19 // account 不存在是初始化出来的,设置 kSecAttrAccount 的 value 20 NSString *account = [wrapper objectForKey:(id)kSecAttrAccount]; 21 if (!account || account.length == 0) { 22 [wrapper setObject:@"jifeifei" forKey:(id)kSecAttrAccount]; 23 } 24 // uuid 不存在是初始化出来的 设置 kSecValueData 的 Value 25 NSString *uuid = [wrapper objectForKey:(id)kSecValueData]; 26 if (!uuid || uuid.length == 0) { 27 uuid = [[[UIDevice currentDevice].identifierForVendor.UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""] lowercaseString]; 28 [wrapper setObject:uuid forKey:(id)kSecValueData]; 29 } 30 31 [self attempt]; 32 33 return YES; 34 }

    4 获得IDFA方法 如果打开限制广告追踪标识符会出现取不到IDFA的情况

    1  #import <AdSupport/AdSupport.h>
    2 
    3   NSString *adId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

    5 直接使用KeyChain保存数据

      使用keyChain保存数据的三个方法:

        // 添加保存的数据    
        SecItemAdd(CFDictionaryRef  _Nonnull attributes, <#CFTypeRef  _Nullable * _Nullable result#>)
        // 删除保存的数据    
        SecItemDelete(<#CFDictionaryRef  _Nonnull query#>)
        // 更新保存的数据    
        SecItemUpdate(CFDictionaryRef  _Nonnull query, <#CFDictionaryRef  _Nonnull attributesToUpdate#>)
        // 获取保存的数据
        SecItemCopyMatching(<#CFDictionaryRef  _Nonnull query#>, <#CFTypeRef  _Nullable * _Nullable result#>)
    #import <Foundation/Foundation.h>
    
    @interface FFKeyChain : NSObject
    + (void)save:(NSString *)serve data:(id)Data;
    + (id)read:(NSString *)serve;
    @end
    
    
    
    #import "FFKeyChain.h"
    
    @implementation FFKeyChain
    /*
     
     https://blog.csdn.net/zhoushuangjian511/article/details/78583429
     
     https://www.cnblogs.com/whyandinside/p/3303108.html
     kSecAttrAccessible: 属性控制keychain中的Item什么时候可以被访问。可选值有 kSecAttrAccessibleWhenUnlocked, kSecAttrAccessibleAfterFirstUnlock, kSecAttrAccessibleAlways, kSecAttrAcessibleWhenUnlockedThisDeviceOnly, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, kSecAttrAccessibleAlwaysThisDeviceOnly
     带有ThisDeviceOnly的意思是如果手机使用其他device的备份restore了之后这些Item就不存在了。
     
     kSecAttrAccessGroup: 如果希望,keychain的item可以被多个应用share, 可以给Item设置这个属性, 类型是CFStringRef, 应用程序在被编译时,可以在entitlement中指定自己的accessgroup,如果应用中的accessgroup和keyChain item中的Accessgroup名字一直,那么这个应用就可以访问这个item,缺点是:accessgroup是由开发者指定的,他可以故意跟其他应用的accessgroup一样,已达到访问其他应用item的目的。同事还支持 wild card ,如keychain-dumper将自己的accessgroup指定为*,从而可以把keychain中所有的Item都dump出来。
     
     kSecAttrAccount 必须 指定一个字典键,其值为物品的描述属性, 使用此键设置或获得,CFStringRef, 包含账户名
     kSecAttrService 必须 指定一个字典键,其值为物品的描述属性, 使用此键设置或获得,CFStringRef与该项目相关的服务
    
     */
    
    + (NSMutableDictionary *)getKeyChainQuery:(NSString *)serve {
        return [@{(id)kSecClass:(id)kSecClassGenericPassword,
                 (id)kSecAttrAccount:serve,
                 (id)kSecAttrService:serve,
                 (__bridge NSString *)kSecAttrAccessible:(__bridge NSString *)kSecAttrAccessibleAfterFirstUnlock,
                   } mutableCopy];
    }
    
    +(NSMutableDictionary*)keyChainIdentifier:(NSString*)identifier {
        NSMutableDictionary * keyChainMutableDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:(id)kSecClassGenericPassword,kSecClass,identifier,kSecAttrService,identifier,kSecAttrAccount,kSecAttrAccessibleAfterFirstUnlock,kSecAttrAccessible, nil];
        return keyChainMutableDictionary;
    }
    
    
    + (void)save:(NSString *)serve data:(id)Data {
        NSMutableDictionary *mDic = [self keyChainIdentifier:serve];//[self getKeyChainQuery:serve];//;
        SecItemDelete((CFDictionaryRef)mDic);
        [mDic setObject:[NSKeyedArchiver archivedDataWithRootObject:Data] forKey:(id)kSecValueData];
        OSStatus sta = SecItemAdd((__bridge CFDictionaryRef)mDic, NULL);
        if (sta == noErr) {
            NSLog(@"成功。。");
        };
    }
    
    + (void)delete:(NSString *)serve {
        NSMutableDictionary *mdic = [self getKeyChainQuery:serve];
        SecItemDelete((__bridge CFDictionaryRef)mdic);
    }
    
    + (void)neeUpdateServe:(NSString *)server updateValue:(NSString *)value {
        NSMutableDictionary *mdic = [self getKeyChainQuery:server];
        OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)mdic, (__bridge CFDictionaryRef)@{(id)kSecValueData:[NSKeyedArchiver archivedDataWithRootObject:value]});
        if (status == errSecSuccess) {
            NSLog(@"更新成功");
        }else {
            NSLog(@"更新失败");
        }
    }
    + (id)read:(NSString *)serve { id let = nil; NSMutableDictionary *mdic = [self getKeyChainQuery:serve]; [mdic setValue:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; [mdic setValue:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; CFDataRef keyData = nil; if (SecItemCopyMatching((__bridge CFDictionaryRef)mdic, (CFTypeRef *)&keyData) == noErr) { @try{ let = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData]; } @catch (NSException *e) { NSLog(@"Unarchiver of %@ failed %@", serve, e); } @finally { } } if (keyData) { CFRelease(keyData); } return let; } @end
  • 相关阅读:
    reservoid sample 蓄水池问题
    发展中的生命力——Leo鉴书69
    Nagios 监控mysqlserver具体实现过程
    OC可变參数的函数实现va_start、va_end、va_list的使用
    Qt移动应用开发(八):实现跨平台的QML和OpenGL混合渲染
    一个简单RPC框架是怎样炼成的(V)——引入传输层
    Spark编程指南V1.4.0(翻译)
    [Scala随用随学] —— sealed声明的作用
    《快学Scala》第八章 继承
    《快学Scala》第六章 对象 第七章 包和引入
  • 原文地址:https://www.cnblogs.com/jisa/p/6928602.html
Copyright © 2011-2022 走看看