UUIDが既にある場合は存在するUUIDを返します。
ない場合は新たに生成したUUIDを返します。
DataStoreではUserDefaultにuuidを保存しています。
ここは実装に合わせて変更して大丈夫です。
キーチェーンはiTunesにバックアップされない為、機種変更でデータが消えてしまうのでUserDefaultに保存しています。
キーチェーンに保存しなければアプリを消した時にUserDefaultのデータは消えてしまうのでUserDefaultとキーチェーンの両方に値を保存しています。
static NSString * const UUID_Key = @"hoge";
+ (NSString*)getUUID {
NSString *uuidString = nil;
//まずはUserDefaultにUUIDがあるか調べてみる
DataStore* dataStore = [DataStore instance];
if (dataStore.baseData.uuid) {
uuidString = dataStore.baseData.uuid;
NSLog(@"UserDefaultにUUIDがあった場合 %@", uuidString);
}
//ない場合はキーチェーンから探す
else {
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kSecClassGenericPassword, (__bridge id)kSecClass,
UUID_Key, (__bridge id)kSecAttrGeneric,
UUID_Key, (__bridge id)kSecAttrAccount,
[[NSBundle mainBundle] bundleIdentifier],(__bridge id)kSecAttrService,
(__bridge id)kSecMatchLimitOne, (__bridge id)kSecMatchLimit,
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
nil];
CFTypeRef attributesRef = NULL;
OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)query, &attributesRef);
if (result == noErr) {
NSDictionary *attributes = (__bridge_transfer NSDictionary *)attributesRef;
NSMutableDictionary *valueQuery = [NSMutableDictionary dictionaryWithDictionary:attributes];
[valueQuery setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
[valueQuery setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
CFTypeRef passwordDataRef = NULL;
OSStatus result = SecItemCopyMatching((__bridge CFDictionaryRef)valueQuery, &passwordDataRef);
if (result == noErr) {
NSData *passwordData = (__bridge_transfer NSData *)passwordDataRef;
// Assume the stored data is a UTF-8 string.
uuidString = [[NSString alloc] initWithBytes:[passwordData bytes]
length:[passwordData length]
encoding:NSUTF8StringEncoding];
}
}
NSLog(@"UserDefaultにUUIDはない場合 %@", uuidString);
}
if (uuidString == nil) {
// Generate the new UIID
CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
CFRelease(uuidRef);
//以下はuuidが00000000-0000-0000-0000-000000000000になってしまう可能性があるので使わない
//id identifier = [[UIDevice currentDevice] performSelector:@selector(identifierForVendor)];
//uuidString = [identifier performSelector:@selector(UUIDString)];
// UIID must be persistent even if the application is removed from devices
// Use keychain as a storage
NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
(__bridge id)kSecClassGenericPassword, (__bridge id)kSecClass,
UUID_Key, (__bridge id)kSecAttrGeneric,
UUID_Key, (__bridge id)kSecAttrAccount,
[[NSBundle mainBundle] bundleIdentifier], (__bridge id)kSecAttrService,
@"", (__bridge id)kSecAttrLabel,
@"", (__bridge id)kSecAttrDescription,
nil];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 4) {
// kSecAttrAccessible is iOS 4 or later only
// Current device is running on iOS 3.X, do nothing here
} else {
// Set kSecAttrAccessibleAfterFirstUnlock so that background applications are able to access this key.
// Keys defined as kSecAttrAccessibleAfterFirstUnlock will be migrated to the new devices/installations via encrypted backups.
// If you want different UIID per device, use kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly instead.
// Keep in mind that keys defined as kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly will be removed after restoring from a backup.
[query setObject:(__bridge id)kSecAttrAccessibleAfterFirstUnlock forKey:(__bridge id)kSecAttrAccessible];
}
[query setObject:[uuidString dataUsingEncoding:NSUTF8StringEncoding] forKey:(__bridge id)kSecValueData];
OSStatus result = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
if (result != noErr) {
NSLog(@"[ERROR] Couldn't add the Keychain Item. result = %ld query = %@", result, query);
return nil;
}
}
//UUIDをUserDefaultに保存する
dataStore.baseData.uuid = uuidString;
[dataStore saveDatas];
return uuidString;
}