Keychainを使用してiOSのUDID問題を解決

3723 ワード

iOS 5以前はuniqueIdentifierでデバイスのUDIDを取得することができたが、プライバシーの問題でAppleはこの方法でUDIDを取得することを禁止した.
“Do not use the uniqueIdentifier property. To create a unique identifier specific to your app, you can call the CFUUIDCreate function to create a UUID, and write it to the defaults database using the NSUserDefaults class.”
AppleはCFUUIDCreateメソッドを使用してUUIDを作成し、NSUserDefaultsに保存することを提案する.
さらにAppleは、次の2つの方法を提供しています.
  • IFA/IDFA(Identifier for Advertisers)は、アプリケーションが広告を表示し、ユーザーがリセットできることに限られる.
  • IFF/IFFV(Identifier for Vendor):アプリケーションが削除されると、UUIDもリセットされます.
  • ソリューション:
    Keychainを用いる、UUIDをパスワード情報として記憶する.
    大まかな流れ:
    1,AdSupportによりUUIDを取得する(理由AdSupportはアプリケーションを跨ぐことができる)
    + (NSString *)appleIFA {
        NSString *ifa = nil;
        Class ASIdentifierManagerClass = NSClassFromString(@"ASIdentifierManager");
        if (ASIdentifierManagerClass) { // a dynamic way of checking if AdSupport.framework is available
            SEL sharedManagerSelector = NSSelectorFromString(@"sharedManager");
            id sharedManager = ((id (*)(id, SEL))[ASIdentifierManagerClass methodForSelector:sharedManagerSelector])(ASIdentifierManagerClass, sharedManagerSelector);
            SEL advertisingIdentifierSelector = NSSelectorFromString(@"advertisingIdentifier");
            NSUUID *advertisingIdentifier = ((NSUUID* (*)(id, SEL))[sharedManager methodForSelector:advertisingIdentifierSelector])(sharedManager, advertisingIdentifierSelector);
            ifa = [advertisingIdentifier UUIDString];
        }
        return ifa;
    }
    

    2,AdSupportがサポートされていない場合はIFB/Identifier for Vendorを使用する
    + (NSString *)appleIFV {
        if(NSClassFromString(@"UIDevice") && [UIDevice instancesRespondToSelector:@selector(identifierForVendor)]) {
            // only available in iOS >= 6.0
            return [[UIDevice currentDevice].identifierForVendor UUIDString];
        }
        return nil;
    }
    

    3、以上のいずれもサポートされていない場合は、CFUUIDRefを使用して手動でUUIDを作成します.
    + (NSString *)randomUUID {
        if(NSClassFromString(@"NSUUID")) { // only available in iOS >= 6.0
            return [[NSUUID UUID] UUIDString];
        }
        CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
        CFStringRef cfuuid = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
        CFRelease(uuidRef);
        NSString *uuid = [((__bridge NSString *) cfuuid) copy];
        CFRelease(cfuuid);
        return uuid;
    }
    

    最後に、Keychainに追加
    + (void)setValue:(NSString *)value forKey:(NSString *)key inService:(NSString *)service {
        NSMutableDictionary *keychainItem = [[NSMutableDictionary alloc] init];
        keychainItem[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
        keychainItem[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleAlways;
        keychainItem[(__bridge id)kSecAttrAccount] = key;
        keychainItem[(__bridge id)kSecAttrService] = service;
        keychainItem[(__bridge id)kSecValueData] = [value dataUsingEncoding:NSUTF8StringEncoding];
        SecItemAdd((__bridge CFDictionaryRef)keychainItem, NULL);
    }
    

    Provisioning profileを更新すると、Keychain dataが失われるので、UUIDをNSUserDefaultでバックアップする必要があります.
    [[NSUserDefaults standardUserDefaults] setObject:@”123456-1234-1234-12345678” forKey:@"deviceUID"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    

    99%参考Persistent,Cross-Install Device Identifier on iOS:Using Keychain:https://blog.onliquid.com/persistent-device-unique-identifier-ios-keychain
    ソース:https://gist.github.com/miguelcma/e8f291e54b025815ca46 bug,