美文网首页带我飞2swiftiOS开发
使用Keychain解决iOS的UDID问题

使用Keychain解决iOS的UDID问题

作者: 不是谢志伟 | 来源:发表于2015-09-24 16:04 被阅读5864次

    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还提供了两种方法来获取:

    • IFA/IDFA (Identifier for Advertisers),局限就是应用必须是显示了广告,并且用户可以重置.
    • IFV/IDFV (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,那就使用IFV/IDFV (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,看留言可以发现问题

    相关文章

      网友评论

      • WKCaesar:但是KeyChain 可以在多个设备之间共享, 这样怎么办?
      • 673743824302:只要换一个provisioning profile,已发布的项目的 Keychain data就会丢失,是这样吗?
        a2b0a5b174bf:@2204672da139 你好,请问更新了provisioning profile,但是bundle id不变,那么keychain data会丢失吗?

      本文标题:使用Keychain解决iOS的UDID问题

      本文链接:https://www.haomeiwen.com/subject/kfaicttx.html