UUID、UDID和KeyChain

UDID:Unique Device Identifier。它就是苹果IOS设备的唯一识别码,它由40个字符的字母和数字组成。

UUID:Universally Unique Identifier。中文意思是通用唯一识别码。

禁止UDID是苹果为了保护用户的隐私,UUID则是给出的替代方案。


/*设备唯一ID(删除应用后重装ID不变)*/
- (NSString *)UDID
{
    NSString *UDID = [[NSUserDefaults standardUserDefaults] valueForKey:@"UDID"];
    if (!UDID.length) {
        if (self.systemVersion.floatValue >= 7.0) {//在keychain中持久化
            UDID = [self getUDIDFromKeychain];
            if (!UDID.length) {
                UDID = self.identifierForVendor.UUIDString;
                [self setUDIDToKeychain:UDID];
            }
        } else {//MAC地址的MD5串
            UDID = [self.MACAddress MD5EncodedString];
        }
        
        [[NSUserDefaults standardUserDefaults] setValue:UDID forKey:@"UDID"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
    return [UDID stringByReplacingOccurrencesOfString:@"-" withString:@""];
}

/*设备唯一ID(删除应用重装后ID可能变更)*/
- (NSString *)UUID
{
    NSString *UUID = nil;
    if (self.systemVersion.floatValue >= 6.0) {
        UUID = self.identifierForVendor.UUIDString;
    } else {
        UUID = [[NSUserDefaults standardUserDefaults] valueForKey:@"UUID"];
        if (!UUID.length) {
            CFUUIDRef UUIDRef = CFUUIDCreate(NULL);
            UUID = (__bridge NSString *)CFUUIDCreateString(NULL, UUIDRef);
            CFRelease(UUIDRef);
            
            [[NSUserDefaults standardUserDefaults] setValue:UUID forKey:@"UUID"];
            [[NSUserDefaults standardUserDefaults] synchronize];
        }
    }
    return [UUID stringByReplacingOccurrencesOfString:@"-" withString:@""];
}

KeyChain:

通常情况下,我们用NSUserDefaults存储数据信息,但是对于一些私密信息,比如密码、证书等等,就需要使用更为安全的keychain了。keychain里保存的信息不会因App被删除而丢失,在用户重新安装App后依然有效,数据还在。

使用苹果官方发布的KeychainItemWrapper或者SFHFKeychainUtils很方便,需要导入Security.framework。每个ios程序都有一个独立的keychain存储。

在应用里使用使用keyChain,我们需要导入Security.framework ,keychain的操作接口声明在头文件SecItem.h里。直接使用SecItem.h里方法操作keychain,需要写的代码较为复杂,为减轻程序的开发,可以使用一些已经封装好了的工具类:KeychainItemWrapper和 SFHFKeychainUtils。

一、使用工具类
(一)KeychainItemWrapper是apple官方例子“GenericKeychain”里一个访问keychain常用操作的封装类,在官网上下载了GenericKeychain项目后,只需要把“KeychainItemWrapper.h”和“KeychainItemWrapper.m”拷贝到我们项目,并导入Security.framework 。KeychainItemWrapper的用法:
 
/** 初始化一个保存用户帐号的KeychainItemWrapper */
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"Account Number"
                                                                                                     accessGroup:@"YOUR_APP_ID_HERE.com.yourcompany.AppIdentifier"];  
 
//保存帐号
[wrapper setObject:@"<帐号>" forKey:(id)kSecAttrAccount];    
 
//保存密码
[wrapper setObject:@"<帐号密码>" forKey:(id)kSecValueData];    
 
//从keychain里取出帐号密码
NSString *password = [wrapper objectForKey:(id)kSecValueData];      
 
//清空设置
[wrapper resetKeychainItem];
其中方法“- (void)setObject:(id)inObject forKey:(id)key;”里参数“forKey”的值应该是Security.framework 里头文件“SecItem.h”里定义好的key,用其他字符串做key程序会崩溃!
 
(二)SFHFKeychainUtils 提供了在 iOS keychain中安全的存储密码的工具
 
 Demo:下载地址https://github.com/ldandersen/scifihifi-iphone/tree/master/security
 
1、引入Security.frameWork框架。
 
2、引入头文件:SFHKeychainUtils.h.
 
3、存密码:
 
[SFHFKeychainUtils storeUsername:@"dd" andPassword:@"aa"forServiceName:SERVICE_NAME updateExisting:1 error:nil];
 
[SFHFKeychainUtils deleteItemForUsername:@"dd" andServiceName:SERVICE_NAME error:nil];
 
4、取密码:
 
NSString *passWord =  [SFHFKeychainUtils getPasswordForUsername:@"dd"andServiceName:SERVICE_NAME error:nil];
 
 
二、使用SecItem.h里方法操作keychain
(以下全为copy,向Keith Harrison致意,http://useyourloaf.com/blog/2010/03/29/simple-iphone-keychain-access.html)
 

 Getting Started

A couple of housekeeping items to get started:

  • Add the “Security.framework” framework to your iPhone application
  • Include the header file <Security/Security.h>

The Basic Search Dictionary

All of the calls to the keychain services make use of a dictionary to define the attributes of the keychain item you want to find, create, update or delete. So the first thing we will do is define a function to allocate and construct this dictionary for us:
static NSString *serviceName = @"com.mycompany.myAppServiceName";

- (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier {
  NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];  

  [searchDictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass];

  NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
  [searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrGeneric];
  [searchDictionary setObject:encodedIdentifier forKey:(id)kSecAttrAccount];
  [searchDictionary setObject:serviceName forKey:(id)kSecAttrService];

  return searchDictionary;
}

Searching the keychain

To find out if our password already exists in the keychain (and what the value of the password is) we use the SecItemCopyMatching function. But first we add a couple of extra items to our basic search dictionary:

- (NSData *)searchKeychainCopyMatching:(NSString *)identifier {
  NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];

  // Add search attributes
  [searchDictionary setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit];

  // Add search return types
  [searchDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];

  NSData *result = nil;
  OSStatus status = SecItemCopyMatching((CFDictionaryRef)searchDictionary,
                                        (CFTypeRef *)&result);

  [searchDictionary release];
  return result;
}

Creating an item in the keychain

Adding an item is almost the same as the previous examples except that we need to set the value of the password we want to store

- (BOOL)createKeychainValue:(NSString *)password forIdentifier:(NSString *)identifier {
  NSMutableDictionary *dictionary = [self newSearchDictionary:identifier];

  NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
  [dictionary setObject:passwordData forKey:(id)kSecValueData];

  OSStatus status = SecItemAdd((CFDictionaryRef)dictionary, NULL);
  [dictionary release];

  if (status == errSecSuccess) {
    return YES;
  }
  return NO;
}

Updating a keychain item

Updating a keychain is similar to adding an item except that a separate dictionary is used to contain the attributes to be updated. Since in our case we are only updating a single attribute (the password) this is easy:

- (BOOL)updateKeychainValue:(NSString *)password forIdentifier:(NSString *)identifier {

  NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
  NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
  NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
  [updateDictionary setObject:passwordData forKey:(id)kSecValueData];

  OSStatus status = SecItemUpdate((CFDictionaryRef)searchDictionary,
                                  (CFDictionaryRef)updateDictionary);

  [searchDictionary release];
  [updateDictionary release];

  if (status == errSecSuccess) {
    return YES;
  }
  return NO;
}
 

Deleting an item from the keychain

The final (and easiest) operation is to delete an item from the keychain using the SecItemDelete function and our usual search dictionary:

- (void)deleteKeychainValue:(NSString *)identifier {

  NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
  SecItemDelete((CFDictionaryRef)searchDictionary);
  [searchDictionary release];
}

 

 参看:http://blog.csdn.net/yiyaaixuexi/article/details/7688745
 
 
 
 
 
 
原文地址:https://www.cnblogs.com/liuziyu/p/4185410.html