UIDevice uniqueIdentifier已弃用 - 现在该怎么办?

Oli*_*ain 498 deprecated uidevice ios

刚刚看到UIDevice uniqueIdentifier属性iOS 5中已弃用,在iOS 7及更高版本中不可用.似乎没有替代方法或财产可用或即将出现.

我们的许多现有应用程序都严格依赖此属性来唯一标识特定设备.我们如何处理这个问题呢?

2011 - 2012文件中的建议是:

特别注意事项

不要使用uniqueIdentifier属性.要创建特定于应用程序的唯一标识符,可以调用该CFUUIDCreate函数创建一个UUID,并使用NSUserDefaults该类将其写入默认数据库.

但是,如果用户卸载并重新安装应用程序,则此值将不同.

Dar*_*ust 271

如果用户卸载并重新安装应用程序,CFUUIDCreate 创建的UUID 唯一的:每次都会获得一个新的UUID .

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

编辑:当然,需要始终查询同一界面的MAC.我想最好的选择是en0.即使接口没有IP /关闭,MAC也始终存在.

编辑2:正如其他人所指出的,iOS 6以来的首选解决方案是- [UIDevice identifierForVendor].在大多数情况下,您应该能够将其用作旧版本的替代品-[UIDevice uniqueIdentifier](但是第一次启动应用时创建的UUID是Apple似乎希望您使用的).

编辑3:所以这个主要观点不会在评论噪声中丢失:不要使用MAC作为UUID,使用MAC创建哈希.每次都会创建相同的结果,即使在重新安装和应用程序中也是如此(如果散列以相同的方式完成).无论如何,现在(2013)除了在iOS <6.0上需要"稳定"的设备标识符之外,这是不再需要的.

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

  • 根据用户是否通过Wifi连接,mac地址是否不会改变? (7认同)
  • @Roger Nolan:请不要编辑其他人的答案,并添加看起来像原作者的内容.谢谢. (3认同)
  • Apple现在拒绝使用散列MAC的应用程序. (3认同)
  • @RogerNolan只要帖子不是社区答案,编辑就是为了纠正错误等事情,而不是添加新内容.你有获得这项特权的原因.想象一下,我编辑你的答案并写一些BS,人们会认为你会写的.我怀疑你是否喜欢这样:-)但是你没有得到通知_that_编辑发生了,我只是偶然发现了. (2认同)

Ser*_*tov 91

UDID已经可以使用Apple的替代品.亲切的家伙gekitz写了类别UIDevice,将UDID根据设备mac-address和bundle标识符生成某种类型.

你可以在github上找到代码

  • 从iOS 7开始,当您在任何设备上请求MAC地址时,系统始终返回值"02:00:00:00:00:00".请点击此处:https://developer.apple.com/library/prerelease/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS7.html#//apple_ref/doc/uid/TP40013162-SW34 (15认同)
  • 虽然它使用了旧式bsd许可证和广告条款,但是. (8认同)
  • 对于现在找到这篇文章的其他人,自上述评论以来jbtule已经更改了许可证. (7认同)
  • 这种实现对于重新安装的设备是唯一的(MAC地址),例如Apple的uniqueId,但也尊重隐私,对于应用程序也是唯一的(也使用bundleId)......必须有imho,Apple应该包含在其API中. ..而不是弃用任何替代品. (3认同)

Mat*_*Mat 61

根据@moonlight提出的链接,我做了几次测试,似乎是最好的解决方案.正如@DarkDust所说,该方法将检查en0哪个始终可用.
有两个选项:
uniqueDeviceIdentifier(MAC + CFBundleIdentifier的MD5 )
uniqueGlobalDeviceIdentifier(MAC的MD5),它们总是返回相同的值.
在我完成的测试之下(使用真实设备):

#import "UIDevice+IdentifierAddition.h"

NSLog(@"%@",[[UIDevice currentDevice] uniqueDeviceIdentifier]);
NSLog(@"%@",[[UIDevice currentDevice] uniqueGlobalDeviceIdentifier]);
Run Code Online (Sandbox Code Playgroud)

XXXX21f1f19edff198e2a2356bf4XXXX - (WIFI)UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (WIFI)GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (3G)UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (3G)GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (GPRS)UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (GPRS)GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (AirPlane模式)UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (AirPlane模式)GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - 删除并安装应用程序后删除并重新安装应用程序XXXX7dc3c577446a2bcbd77935bdXXXX(Wi-Fi)后的(Wi-Fi)

希望它有用.

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

  • 这不适用于iOS7,Apple消除了MAC地址的使用. (13认同)
  • 感谢额外的努力来测试这个! (11认同)

小智 56

看一下这个,

我们可以使用Keychain而不是NSUserDefaultsclass来存储UUID创建的CFUUIDCreate.

通过这种方式,我们可以避免UUID重新安装娱乐,并获得UUID相同的应用程序甚至用户卸载并重新安装相同.

UUID 将在用户重置设备时重新创建.

我用SFHFKeychainUtils尝试了这个方法,它就像一个魅力.

  • 此方法是UDID的可靠替代品.它还具有在设备格式上重新创建标识符的额外好处(例如,如果设备改变了所有者).但是,重要的是要注意,如果用户加密其备份,则可以将钥匙串还原到其他设备.这可能导致多个设备共享相同UUID的情况.要避免这种情况,请将钥匙串项的可访问性设置为"kSecAttrAccessibleAlwaysThisDeviceOnly".这将确保您的UUID不会迁移到任何其他设备.要从其他应用程序访问您的UUID,请使用`kSecAttrAccessGroup`键. (32认同)

Sam*_*han 48

创建自己的UUID,然后将其存储在Keychain中.因此,即使您的应用程序被卸载,它仍然存在.在许多情况下,即使用户在设备之间迁移(例如完全备份和还原到另一个设备),它也会持续存在.

实际上,只要您担心,它就会成为唯一的用户标识符.(甚至比设备标识符更好).

例:

我正在定义一个创建UUIDas 的自定义方法:

- (NSString *)createNewUUID 
{
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return [(NSString *)string autorelease];
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以在KEYCHAIN首次启动应用时将其存储.因此,首次启动后,我们可以简单地从钥匙串使用它,无需重新生成它.使用Keychain存储的主要原因是:当您设置UUIDKeychain时,即使用户完全卸载App然后再次安装,它也会持续存在..因此,这是存储它的永久方式,这意味着密钥将一直是唯一的.

     #import "SSKeychain.h"
     #import <Security/Security.h>
Run Code Online (Sandbox Code Playgroud)

在应用程序启动时包括以下代码:

 // getting the unique key (if present ) from keychain , assuming "your app identifier" as a key
       NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];
      if (retrieveuuid == nil) { // if this is the first time app lunching , create key for device
        NSString *uuid  = [self createNewUUID];
// save newly created key to Keychain
        [SSKeychain setPassword:uuid forService:@"your app identifier" account:@"user"];
// this is the one time process
}
Run Code Online (Sandbox Code Playgroud)

sskeychain下载SSKeychain.m和.h文件 并将SSKeychain.m和.h文件拖到项目中,并将"Security.framework"添加到项目中.之后使用UUID只需使用:

NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];
Run Code Online (Sandbox Code Playgroud)

  • 在卸载/重新安装周期+验证苹果应用程序提交后,任何有效的人都在使用iOS7吗? (3认同)

小智 17

也许你可以使用:

[UIDevice currentDevice].identifierForVendor.UUIDString
Run Code Online (Sandbox Code Playgroud)

Apple的文档描述了identifierForVender,如下所示:

对于来自同一设备上运行的同一供应商的应用,此属性的值相同.对于来自不同供应商的同一设备上的应用程序以及不同供应商的不同设备上的应用程序,将返回不同的值.


小智 14

您可能需要考虑使用OpenUDID哪个是已弃用的替代品UDID.

基本上,要匹配UDID,需要以下功能:

  1. 独特或足够独特(低概率碰撞可能是非常可接受的)
  2. 重新启动,恢复,卸载时的持久性
  3. 适用于不同供应商的应用程序(通过CPI网络获取用户非常有用) -

OpenUDID 实现上述目标,甚至还有一个内置的Opt-Out机制供以后考虑.

检查http://OpenUDID.org它指向相应的GitHub.希望这可以帮助!

作为旁注,我会回避任何MAC地址替代方案.虽然MAC地址看起来像一个诱人的通用解决方案,但请确保这种低悬的水果中毒.MAC地址非常敏感,Apple甚至可以拒绝访问此地址,甚至可以说"提交此应用程序"...... MAC网络地址用于验证私有设备(WLAN)或其他虚拟专用设备上的某些设备网络(VPN)...它比以前的UDID更敏感!


Mat*_*ers 11

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

  • 生成UUID并存储在用户默认值中?不好,因为当用户删除应用程序时,这不会持续存在.如果稍后再次安装,则在线服务不应创建新设备记录,这会浪费服务器上的资源并提供包含相同设备的设备列表两次或更多次.如果他们重新安装应用程序,用户会看到列出多个"Bob的iPhone".

  • 生成UUID并存储在钥匙串中?这是我的计划,因为它甚至在卸载应用程序时仍然存在.但是,当将iTunes备份恢复到新的iOS设备时,如果备份已加密,则会传输钥匙串.如果旧设备和新设备都在使用中,这可能导致两个设备包含相同的设备ID.这些应该在在线服务中列为两个设备,即使设备名称相同.

  • 生成MAC地址和包ID的哈希值?这看起来是我需要的最佳解决方案.通过使用包ID进行散列,生成的设备ID不会启用跨应用程序跟踪设备,我会获得应用程序+设备组合的唯一ID.

有趣的是,Apple自己的文档是指通过计算系统MAC地址的散列加上捆绑包ID和版本来验证Mac App Store收据.所以这似乎是政策所允许的,无论是通过我还不知道的应用评论.

  • 要避免第二点中描述的情况,请将钥匙串项的可访问性设置为"kSecAttrAccessibleAlwaysThisDeviceOnly".这将确保您的UUID不会还原到其他设备,即使备份已加密. (10认同)

Nat*_*ate 11

看起来对于iOS 6,Apple建议您使用NSUUID类.

从现在UIDevice docs for uniqueIdentifierproperty中的消息:

在iOS 5.0中不推荐使用.请根据需要使用此类的identifierForVendor属性或ASIdentifierManager类的advertisingIdentifier属性,或使用NSUUID类的UUID方法创建UUID并将其写入用户默认数据库.


Ash*_*iya 11

可以提供帮助:使用以下代码,除了擦除(格式化)您的设备外,它始终是唯一的.

UIDevice *myDevice=[UIDevice currentDevice];
NSString *UUID = [[myDevice identifierForVendor] UUIDString];
Run Code Online (Sandbox Code Playgroud)


cho*_*own 7

我还建议转换uniqueIdentifier这个开源库(真正的2个简单类别),利用设备的MAC地址和应用程序包标识符在您的应用程序中生成可用作UDID替换的唯一ID.

请记住,与UDID不同,这个数字对于每个应用都会有所不同.

您只需要导入包含NSStringUIDevice类别并调用[[UIDevice currentDevice] uniqueDeviceIdentifier]如下:

#import "UIDevice+IdentifierAddition.h"
#import "NSString+MD5Addition.h"
NSString *iosFiveUDID = [[UIDevice currentDevice] uniqueDeviceIdentifier]
Run Code Online (Sandbox Code Playgroud)

你可以在Github上找到它:

适用于iOS 5的UIDevice和UniqueIdentifier


以下是类别(只是.m文件 - 检查标头的github项目):

的UIDevice + IdentifierAddition.m

#import "UIDevice+IdentifierAddition.h"
#import "NSString+MD5Addition.h"

#include <sys/socket.h> // Per msqr
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>

@interface UIDevice(Private)

- (NSString *) macaddress;

@end

@implementation UIDevice (IdentifierAddition)

////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Private Methods

// Return the local MAC addy
// Courtesy of FreeBSD hackers email list
// Accidentally munged during previous update. Fixed thanks to erica sadun & mlamb.
- (NSString *) macaddress{
    
    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;
    
    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;
    
    if ((mib[5] = if_nametoindex("en0")) == 0) {
        printf("Error: if_nametoindex error\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }
    
    if ((buf = malloc(len)) == NULL) {
        printf("Could not allocate memory. error!\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2");
        return NULL;
    }
    
    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 
                           *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
    free(buf);
    
    return outstring;
}

////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Public Methods

- (NSString *) uniqueDeviceIdentifier{
    NSString *macaddress = [[UIDevice currentDevice] macaddress];
    NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];  
    NSString *stringToHash = [NSString stringWithFormat:@"%@%@",macaddress,bundleIdentifier];
    NSString *uniqueIdentifier = [stringToHash stringFromMD5];  
    return uniqueIdentifier;
}

- (NSString *) uniqueGlobalDeviceIdentifier{
    NSString *macaddress = [[UIDevice currentDevice] macaddress];
    NSString *uniqueIdentifier = [macaddress stringFromMD5];    
    return uniqueIdentifier;
}

@end
Run Code Online (Sandbox Code Playgroud)

的NSString + MD5Addition.m:

#import "NSString+MD5Addition.h"
#import <CommonCrypto/CommonDigest.h>

@implementation NSString(MD5Addition)

- (NSString *) stringFromMD5{
    
    if(self == nil || [self length] == 0)
        return nil;
    
    const char *value = [self UTF8String];
    
    unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5(value, strlen(value), outputBuffer);
    
    NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
        [outputString appendFormat:@"%02x",outputBuffer[count]];
    }
    return [outputString autorelease];
}

@end
Run Code Online (Sandbox Code Playgroud)

  • 从iOS 7开始,Apple将返回MAC地址的常量值.这很有道理.MAC地址很敏感. (3认同)

Sac*_*hin 5

您可以通过以下代码实现:UIDevice-with-UniqueIdentifier-for-iOS-5