刚刚发现,UIDevice uniqueIdentifier属性在iOS 5中已弃用,在iOS 7及以上版本中不可用。似乎没有可供选择的方法或属性。

我们现有的许多应用程序都紧密依赖于这个属性来唯一地识别特定的设备。今后我们该如何处理这个问题?

2011-2012年的文件建议:

特殊注意事项 不要使用uniqueIdentifier属性。创建特定的唯一标识符 你可以调用CFUUIDCreate函数来创建一个UUID,然后写入 使用NSUserDefaults类将它转换到默认数据库。

但是,如果用户卸载和重新安装应用程序,这个值就不一样了。


当前回答

我也遇到了一些问题,解决方法很简单:

    // Get Bundle Info for Remote Registration (handy if you have more than one app)
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
    NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];


    // Get the users Device Model, Display Name, Unique ID, Token & Version Number
    UIDevice *dev = [UIDevice currentDevice];
    NSString *deviceUuid=[dev.identifierForVendor  UUIDString];

    NSString *deviceName = dev.name;

其他回答

我相信苹果公司的这一变化惹恼了很多人。我开发了一个iOS的簿记应用程序,并有一个在线服务来同步不同设备上的更改。该服务维护所有设备的数据库以及需要传播到这些设备的更改。因此,了解哪种设备是哪种设备很重要。我使用UIDevice uniqueIdentifier跟踪设备,为了它的价值,这里是我的想法。

Generate a UUID and store in user defaults? No good because this does not persist when the user deletes the app. If they install again later the online service should not create a new device record, that would waste resources on the server and give a list of devices containing the same one two or more times. Users would see more than one "Bob's iPhone" listed if they re-installed the app. Generate a UUID and store in the keychain? This was my plan, since it persists even when the app is uninstalled. But when restoring an iTunes backup to a new iOS device, the keychain is transferred if the backup is encrypted. This could lead to two devices containing the same device id if the old and new devices are both in service. These should be listed as two devices in the online service, even if the device name is the same. Generate a hash the MAC address and bundle id? This looks like the best solution for what I need. By hashing with the bundle id, the generated device id is not going to enable the device to be tracked across apps and I get a unique ID for the app+device combination.

有趣的是,苹果自己的文档提到通过计算系统Mac地址加上bundle id和版本的哈希来验证Mac App Store收据。所以这似乎是政策允许的,但是否通过应用审查我还不知道。

根据@moonlight提出的链接,我做了几次测试,这似乎是最好的解决方案。正如@DarkDust所说,该方法将检查始终可用的en0。 有两种选择: uniqueDeviceIdentifier (MAC+CFBundleIdentifier的MD5) 和uniqueGlobalDeviceIdentifier(MAC的MD5),这些总是返回相同的值。 下面是我所做的测试(用真正的设备):

#import "UIDevice+IdentifierAddition.h"

NSLog(@"%@",[[UIDevice currentDevice] uniqueDeviceIdentifier]);
NSLog(@"%@",[[UIDevice currentDevice] uniqueGlobalDeviceIdentifier]);

XXXX21f1f19edff198e2a2356bf4XXXX - (WIFI)UDID XXXX7dc3c577446a2bcbd77935bdXXXX - (WIFI)GlobalAppUDID XXXX21f1f19edff198e2a2356bf4XXXX - (3G)UDID XXXX7dc3c577446a2bcbd77935bdXXXX - (3G)GlobalAppUDID XXXX21f1f19edff198e2a2356bf4XXXX - (GPRS)UDID XXXX7dc3c577446a2bcbd77935bdXXXX - (GPRS)GlobalAppUDID XXXX21f1f19edff198e2a2356bf4XXXX - (AirPlane mode)UDID XXXX7dc3c577446a2bcbd77935bdXXXX - (AirPlane mode)GlobalAppUDID XXXX21f1f19edff198e2a2356bf4XXXX - (Wi-Fi)after removing and reinstalling the app XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) after removing and installing the app

希望对大家有用。

编辑: 正如其他人指出的那样,这个解决方案在iOS 7中不再有用,因为uniqueIdentifier不再可用,查询MAC地址现在总是返回02:00:00:00:00:00

使用上面提到的SSKeychain和代码。下面是复制/粘贴(添加SSKeychain模块)的代码:

+(NSString *) getUUID {

//Use the bundle name as the App identifier. No need to get the localized version.

NSString *Appname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];    

//Check if we have UUID already

NSString *retrieveuuid = [SSKeychain passwordForService:Appname account:@"user"];

if (retrieveuuid == NULL)
{

    //Create new key for this app/device

    CFUUIDRef newUniqueId = CFUUIDCreate(kCFAllocatorDefault);

    retrieveuuid = (__bridge_transfer NSString*)CFUUIDCreateString(kCFAllocatorDefault, newUniqueId);

    CFRelease(newUniqueId);

    //Save key to Keychain
    [SSKeychain setPassword:retrieveuuid forService:Appname account:@"user"];
}

return retrieveuuid;

}

虽然不完美,但却是UDID的最佳和最接近的替代品之一(在Swift中使用iOS 8.1和Xcode 6.1):

生成一个随机UUID

let strUUID: String = NSUUID().UUIDString

并使用KeychainWrapper库:

给keychain添加一个字符串值:

let saveSuccessful: Bool = KeychainWrapper.setString("Some String", forKey: "myKey")

从keychain中检索字符串值:

let retrievedString: String? = KeychainWrapper.stringForKey("myKey")

从keychain中删除一个字符串值:

let removeSuccessful: Bool = KeychainWrapper.removeObjectForKey("myKey")

该解决方案使用了keychain,因此存储在keychain中的记录将被持久化,即使在应用程序卸载和重新安装之后。删除该记录的唯一方法是重置设备的所有内容和设置。这就是为什么我提到这个替代方案并不完美,但仍然是iOS 8.1上使用Swift替代UDID的最佳方案之一。

如果用户卸载和重新安装应用程序,CFUUIDCreate创建的UUID是唯一的:你每次都会得到一个新的UUID。

但你可能希望它不是唯一的,即它应该保持不变,当用户卸载和重新安装应用程序。这需要一些努力,因为最可靠的每个设备标识符似乎是MAC地址。您可以查询MAC并使用它作为UUID。

编辑:当然,总是需要查询同一接口的MAC。我想最好的选择是en0。MAC一直存在,即使接口没有IP/ down。

编辑2:正如其他人指出的那样,自iOS 6以来首选的解决方案是-[UIDevice identifierForVendor]。在大多数情况下,你应该可以使用它来替换旧的-[UIDevice uniqueIdentifier](但是当应用程序第一次启动时创建的UUID似乎是苹果想要你使用的)。

编辑3:所以这个重点不会在评论噪音中丢失:不要使用MAC作为UUID,使用MAC创建哈希。哈希每次都会创建相同的结果,即使是在重新安装和应用程序之间(如果哈希以相同的方式完成)。不管怎样,现在(2013年)这已经没有必要了,除非你在iOS < 6.0上需要一个“稳定的”设备标识符。

编辑4:在iOS 7中,苹果现在在查询MAC时总是返回一个固定值,以专门阻止MAC作为ID方案的基础。所以你现在应该使用-[UIDevice identifierForVendor]或者创建一个每个安装的UUID。