トップ «前の日記(2012-08-04) 最新 次の日記(2012-08-12)» 編集

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|

2012-08-08 [iOS]ユニークID (2)

前回、UUIDをユニークIDとして利用する方法を紹介したが、UUIDは取得する度に異なる値となる為、そのアプリケーションにとて、インストールされたiOS機器でユニークで固定なIDとして利用できない。

そこで、UUIDをキーチェインに登録して、そのアプリケーションにとってユニークで固定なIDにするコードを紹介する。まずは、Secuirty.frameworkをプロジェクトに追加する。


#import <Security/Security.h>
 
@interface ViewController ()
- (NSString *)createUUID;
- (NSString *)loadKeychainServices;
- (void)removeKeychainService;
@end
 
@implementation ViewController
 
- (void)viewDidLoad
{
    [super viewDidLoad];
    NSString    *uuidString = [self loadKeychainServices];
    NSLog(@"UUID:%@", uuidString);
    uuidString = [self loadKeychainServices];
    NSLog(@"UUID:%@", uuidString);
    [self removeKeychainService];
    uuidString = [self loadKeychainServices];
    NSLog(@"UUID:%@", uuidString);
}
 
- (NSString *)createUUID
{
    CFUUIDRef   uuid = CFUUIDCreate(NULL);
    NSString    *uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(NULL, uuid);
    CFRelease(uuid);
    return uuidString;
}
 
- (NSString *)loadKeychainServices
{
    NSString    *savedUUID = nil;
    
    NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
    [query setObject:(id)@"UUID" forKey:(__bridge id)kSecAttrGeneric];
    [query setObject:(id)@"UUID" forKey:(__bridge id)kSecAttrAccount];
    [query setObject:[[NSBundle mainBundle] bundleIdentifier] forKey:(__bridge id)kSecAttrService];
    [query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    [query setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
    [query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes];
    
    CFDictionaryRef attributesDictRef = nil;
    OSStatus    result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&attributesDictRef);
    NSDictionary    *attributes = (__bridge_transfer NSDictionary *)attributesDictRef;
    if (result == noErr) {
        query = [NSMutableDictionary dictionaryWithDictionary:attributes];
        [query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
        [query setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
        CFDataRef   dataRef;
        result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&dataRef);
        NSData  *data = (__bridge_transfer NSData *)dataRef;
        if (result == noErr) {
            savedUUID = [[NSString alloc] initWithBytes:[data bytes]
                                                 length:[data length]
                                               encoding:NSUTF8StringEncoding];
        }
    }
    if (! savedUUID) {
        savedUUID = [self createUUID];
        query = [[NSMutableDictionary alloc] init];
        [query setObject:(id)@"UUID" forKey:(__bridge id)kSecAttrGeneric];
        [query setObject:(id)@"UUID" forKey:(__bridge id)kSecAttrAccount];
        [query setObject:[[NSBundle mainBundle] bundleIdentifier] forKey:(__bridge id)kSecAttrService];
        [query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
        [query setObject:(id)@"UUID" forKey:(__bridge id)kSecAttrLabel];
        [query setObject:(id)@"UUID" forKey:(__bridge id)kSecAttrDescription];
        [query setObject:(id)[savedUUID dataUsingEncoding:NSUTF8StringEncoding] forKey:(__bridge id)kSecValueData];
        result = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
        if (result != noErr) {
            savedUUID = nil;
        }
    }
    return savedUUID;
}
 
- (void)removeKeychainService
{
    NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
    [query setObject:(id)@"UUID" forKey:(__bridge id)kSecAttrGeneric];
    [query setObject:(id)@"UUID" forKey:(__bridge id)kSecAttrAccount];
    [query setObject:[[NSBundle mainBundle] bundleIdentifier] forKey:(__bridge id)kSecAttrService];
    [query setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    
    OSStatus result = SecItemDelete((__bridge CFDictionaryRef)query);
    if (result != noErr) {
    }
}
 
@end

キーチェインに登録できる情報の種類は決められているので、パスワードとしてUUIDを登録した。

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/UniqueID - GitHub

_ 関連情報

CFUUID Reference

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)

トップ «前の日記(2012-08-04) 最新 次の日記(2012-08-12)» 編集