ChatGPT解决这个技术问题 Extra ChatGPT

不推荐使用 UIDevice uniqueIdentifier - 现在该怎么办?

刚刚发现 the UIDevice uniqueIdentifier property is deprecatediOS 5 中不可用,在 iOS 7 及更高版本中不可用。似乎没有替代方法或财产可用或即将推出。

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

the documentation in 2011-2012 的建议是:

特殊注意事项 不要使用 uniqueIdentifier 属性。要创建特定于您的应用程序的唯一标识符,您可以调用 CFUUIDCreate 函数来创建 UUID,并使用 NSUserDefaults 类将其写入默认数据库。

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

对于仍在使用 uniqueIdentifier 的应用程序,iOS7 现在返回 FFFFFFFF + identifierForVendor,这破坏了许多编写不当的非续订订阅应用程序。
如果幸运的是您的应用程序使用了推送通知,您可以使用从苹果推送服务发回的令牌,它也是每台设备唯一的
@CalinChitu 如果用户不接受推送通知,您是否仍会获得该用户的 pushID?

w
waza

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

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

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

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

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

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


mac地址不会根据用户是否通过Wifi连接而改变吗?
@DarkDust:但是由于从wifi切换到蜂窝调制解调器时活动接口会发生变化,因此活动接口的MAC地址也应该改变;除非你总是选择一个特定的接口来获取 MAC
@Roger Nolan:请不要编辑其他人的答案并添加看起来像是来自原作者的东西。谢谢。
@RogerNolan 只要帖子不是社区答案,编辑是为了纠正错误等,而不是为了添加新东西。您获得特权是有原因的。想象一下,我编辑了您的答案并写了一些废话,人们会认为您会写那个。我怀疑你会喜欢那个:-) 但是你不会收到编辑发生的通知,我只是偶然发现的。
Apple 现在拒绝使用哈希 MAC 的应用程序。
P
Paras Joshi

您已经可以为 Apple UDID 使用您的替代品了。好心人 gekitz 在 UIDevice 上编写了类别,该类别将根据设备 mac-address 和包标识符生成某种 UDID

您可以在 github 上找到代码


对于重新安装的设备,此实现是唯一的(MAC 地址),例如 Apple 的 uniqueId,但也尊重隐私,对于应用程序也是唯一的(也使用 bundleId)... 恕我直言,Apple 应将其包含在其 API 中。 .. 而不是弃用没有任何替代方案。
虽然它使用带有广告条款的旧式 bsd 许可证,但很糟糕。
对于现在找到此帖子的其他任何人,自 jbtule 上述评论以来,许可证已更改。
正如此提交评论中所讨论的,该库原样存在严重的隐私泄露问题,不应使用:
从 iOS 7 开始,当您在任何设备上请求 MAC 地址时,系统总是返回值 02:00:00:00:00:00。在这里检查:developer.apple.com/library/prerelease/ios/releasenotes/General/…
M
Mat

根据@moonlight 提出的链接,我做了几个测试,这似乎是最好的解决方案。正如@DarkDust 所说,该方法会检查始终可用的 en0
有 2 个选项:
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) 删除并重新安装应用程序后 XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) 删除和安装应用程序后

希望它有用。

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


这在 iOS7 上不起作用,Apple 消除了 MAC 地址的使用。
@SarimSidd 目前有关 iOS 7 的信息处于保密协议之下,我们无法在此讨论。
P
Paras Joshi

看一下这个,

我们可以使用 Keychain 而不是 NSUserDefaults 类来存储由 CFUUIDCreate 创建的 UUID

通过这种方式,我们可以避免重新安装重新安装 UUID,并且即使用户卸载并重新安装,相同的应用程序也始终获得相同的 UUID

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

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


此方法是 UDID 的可靠替代品。它还具有根据设备格式重新创建标识符的额外好处(例如,如果设备更改了所有者)。但是,重要的是要注意,如果用户对其备份进行加密,则可以将钥匙串恢复到其他设备。这可能会导致多个设备共享相同的 UUID。为避免这种情况,请将钥匙串项的可访问性设置为 kSecAttrAccessibleAlwaysThisDeviceOnly。这将确保您的 UUID 不会迁移到任何其他设备。要从其他应用程序访问您的 UUID,请使用 kSecAttrAccessGroup 键。
您应该在哪里(哪个键)将 UUID 存储在钥匙串中?
哎呀!链接坏了
a
adib

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

实际上,就您而言,它成为唯一的用户标识符。 (甚至比设备标识符更好)。

例子:

我正在定义用于创建 UUID 的自定义方法:

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

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

     #import "SSKeychain.h"
     #import <Security/Security.h>

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

 // 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
}

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

NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];

因为 identifierForVendor 的工作并不完美。在某些情况下可以返回 nil 或 0x0。这种方法似乎效果很好
卸载/重新安装周期+验证苹果应用程序提交后,有人验证这在 iOS7 上有效吗?
我已经开始使用这个解决方案。在 2 台设备上进行的几次测试(重建、重新安装、设备关闭)表明 id 是相同的。 iOS 10.3。
d
diadyne

也许你可以使用:

[UIDevice currentDevice].identifierForVendor.UUIDString

Apple 的文档对 identifierForVender 的描述如下:

对于来自同一供应商并在同一设备上运行的应用,此属性的值相同。对于来自不同供应商的同一设备上的应用程序以及不同设备上的应用程序(无论供应商)返回不同的值。


很好奇为什么直到最近才有人提出这个......现在我看到它是 iOS 6 的新功能。
如果用户更新 ios 和/或安装新的 ios,那么 identifierForVendor 的值会改变还是保持不变?
从同一供应商处删除所有应用程序后,此值将更改。
P
Paras Joshi

您可能需要考虑使用 OpenUDID,它是已弃用的 UDID 的直接替代品。

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

独特或足够独特(低概率冲突可能非常可接受)在不同供应商的应用程序中可用的重启、恢复、卸载的持久性(有助于通过 CPI 网络获取用户)-

OpenUDID 满足上述要求,甚至具有内置的退出机制供以后考虑。

勾选 http://OpenUDID.org 指向对应的 GitHub。希望这可以帮助!

作为旁注,我会回避任何 MAC 地址替代方案。虽然 MAC 地址看起来像是一种诱人且通用的解决方案,但请确保这种低悬的果实已中毒。 MAC 地址非常敏感,Apple 很可能会在您说“提交此应用程序”之前就弃用此地址... MAC 网络地址用于验证专用局域网 (WLAN) 或其他虚拟专用设备上的某些设备网络(VPN)。 ..它比以前的UDID还要敏感!


我真的很好奇这是如何工作的?代码是用 Objective-C 编写的,但是没有其他适合上述要求的好的解决方案,那么这个框架有什么不同呢?该框架正在使用的解决方案也应该可以在此处作为建议的答案发布...
我同意 - MAC 地址也可以手动配置(“克隆”),尽管在大多数情况下不太可能。我必须抗议 UDID 中的 D。这不是设备 ID,而是 UUID(通用唯一标识符)。设备 ID 由 Apple 出厂时在 ROM 中的每台设备上加盖印记。
iOS7 的最佳解决方案以及唯一识别设备的实际需要
OpenUDID 已弃用,不建议使用
M
Mathew Waters

我敢肯定,Apple 的这一变化已经惹恼了很多人。我为 iOS 开发了一个 bookkeeping app,并有一个在线服务来同步在不同设备上所做的更改。该服务维护所有设备的数据库以及需要传播给它们的更改。因此,重要的是要知道哪些设备是哪些。我正在使用 UIDevice uniqueIdentifier 跟踪设备,对于它的价值,这是我的想法。

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

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

生成MAC地址和捆绑ID的哈希?这看起来是我需要的最佳解决方案。通过使用捆绑 ID 进行哈希处理,生成的设备 ID 不会使设备能够跨应用程序进行跟踪,并且我获得了应用程序+设备组合的唯一 ID。

有趣的是,Apple 自己的文档是指通过计算系统 MAC 地址加上捆绑包 ID 和版本的哈希值来验证 Mac App Store 收据。所以这似乎是政策允许的,我还不知道它是否通过了应用程序审查。


为避免第二点中描述的情况,请将钥匙串项的可访问性设置为 kSecAttrAccessibleAlwaysThisDeviceOnly。这将确保您的 UUID 不会恢复到其他设备,即使备份已加密。
这确实是我见过很多次的行为。例如,我为我的 iPhone 注册了 Google Sync。然后我得到了一部新 iPhone,注册它,瞧——我现在在我的同步设置中列出了 2 部 iPhone。
V
Vasu

看起来对于 iOS 6,Apple 建议您使用 the NSUUID class

现在来自 uniqueIdentifier 属性的 UIDevice 文档中的消息:

在 iOS 5.0 中已弃用。酌情使用此类的 identifierForVendor 属性或 ASIdentifierManager 类的 adsIdentifier 属性,或使用 NSUUID 类的 UUID 方法创建 UUID 并将其写入用户默认数据库。


A
Ashvin A

可能会有所帮助:使用下面的代码它将始终是唯一的,除非您擦除(格式化)您的设备。

目标-C:

选项 1:这将在每次安装时更改

UIDevice *uuid = [NSUUID UUID].UUIDString;

选项 2:这对于每个供应商/开发者 Apple 帐户都是唯一的

UIDevice *myDevice = [UIDevice currentDevice];
NSString *uuid = [[myDevice identifierForVendor] UUIDString];

斯威夫特 5.X:

选项 1:这将在每次安装时更改

let uuid = UUID().uuidString

选项 2:这对于每个供应商/开发者 Apple 帐户都是唯一的

let myDevice = UIDevice.current
let uuid = myDevice.identifierForVendor?.uuidString

我使用了这段代码。但是当我删除应用程序并再次安装时,我得到了新的 ID
如果您不需要强大的方法,这是一个简单的解决方案。我现在在我的应用程序中使用它。
@Durgaprasad:它总是会改变,因为它依赖于供应商。例如: 1. 如果您安装了一个带有 bundleidenedifier 的应用程序:com.abcd.com => 那么它会改变。 2.如果你已经安装了两个带有bundleidenedifier的应用程序:com.abcd.com => 那么它不会改变(保持任何一个应用程序期间)
N
NANNAV

我还建议从 uniqueIdentifier 更改为 this open source library(实际上是 2 个简单的类别),它利用设备的 MAC 地址和 App Bundle Identifier 在您的应用程序中生成一个唯一 ID,可以用作 UDID 替代品。

请记住,与 UDID 不同,这个数字对于每个应用程序都是不同的。

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

#import "UIDevice+IdentifierAddition.h"
#import "NSString+MD5Addition.h"
NSString *iosFiveUDID = [[UIDevice currentDevice] uniqueDeviceIdentifier]

你可以在 Github 上找到它:

UIDevice with UniqueIdentifier for iOS 5

以下是类别(仅 .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

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

从 iOS 7 开始,Apple 将为 MAC 地址返回一个常量值。这很有意义。 MAC 地址是敏感的。
D
DD_

您可以从此代码实现:UIDevice-with-UniqueIdentifier-for-iOS-5


T
Toastor

MAC 地址可以被欺骗,这使得这种方法无法将内容绑定到特定用户或实施黑名单等安全功能。

经过一些进一步的研究,在我看来,到目前为止我们还没有合适的选择。我真诚地希望苹果能够重新考虑他们的决定。

也许向 Apple 发送有关此主题的电子邮件和/或对此提出错误/功能请求是一个好主意,因为他们甚至可能不知道对开发人员的全部后果。


一个有效的观点,但我相信 UUID 也可以在越狱的手机上被欺骗/调换,所以从技术上讲,现有的 [UIDevice uniqueIdentifier] 也同样存在缺陷。
您始终可以在服务器上创建标识符并将其保存在设备上。大多数应用程序就是这样做的。我不明白为什么 iOS 程序员需要一些特别的东西。
@Sulthan 在 iOS 上不起作用,因为如果您卸载应用程序,其所有数据都将消失,因此无法以这种方式保证设备标识符的唯一性。
如果您将其保存到钥匙串,则不会。无论如何,我从未见过有此问题的应用程序。如果应用程序和数据已被删除,则您不需要相同的设备标识符。如果您想识别用户,请向他索要电子邮件。
苹果在 iOS 的新版本中也禁止了 MAC 地址访问;
D
DD_

iOS 6 中引入的 UIDevice identifierForVendor 将适用于您的目的。

identifierForVendor 是一个字母数字字符串,用于向应用程序的供应商唯一标识设备。 (只读)

@property(nonatomic, readonly, retain) NSUUID *identifierForVendor

对于来自同一供应商并在同一设备上运行的应用,此属性的值相同。对于来自不同供应商的同一设备上的应用程序以及不同设备上的应用程序(无论供应商)返回不同的值。

在 iOS 6.0 及更高版本中可用并在 UIDevice.h 中声明

对于 iOS 5,请参阅此链接 UIDevice-with-UniqueIdentifier-for-iOS-5


K
Komposr

使用上面提到的 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;

}


s
santify

以下代码有助于获取 UDID:

        udid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
        NSLog(@"UDID : %@", udid);

G
Grzegorz Krukowski

这是我用来获取 iOS 5 和 iOS 6、7 的 ID 的代码:

- (NSString *) advertisingIdentifier
{
    if (!NSClassFromString(@"ASIdentifierManager")) {
        SEL selector = NSSelectorFromString(@"uniqueIdentifier");
        if ([[UIDevice currentDevice] respondsToSelector:selector]) {
            return [[UIDevice currentDevice] performSelector:selector];
        }
    }
    return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}

您如何处理编译器警告 PerformSelector may cause a leak because its selector is unknown
您不能再为此目的使用 adsIdentifier,因为 Apple 会拒绝它。更多信息:techcrunch.com/2014/02/03/…
N
NANNAV

从 iOS 6 开始,我们有符合 RFC4122NSUUID

苹果链接:apple_ref for NSUUID


S
Santosh Botre

iOS 11 引入了 DeviceCheck 框架。它具有用于唯一识别设备的完整解决方案。


C
Community

获取 UDID 的一种工作方式:

在应用程序内启动一个带有两个页面的 Web 服务器:一个应该返回特制的 MobileConfiguration 配置文件,另一个应该收集 UDID。更多信息在这里,这里和这里。您从应用程序内部打开 Mobile Safari 的第一页,它会将您重定向到 Settings.app 要求安装配置文件。安装配置文件后,UDID 将发送到第二个网页,您可以从应用程序内部访问它。 (Settings.app 具有所有必要的权利和不同的沙盒规则)。

使用 RoutingHTTPServer 的示例:

import UIKit
import RoutingHTTPServer

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var bgTask = UIBackgroundTaskInvalid
    let server = HTTPServer()

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        application.openURL(NSURL(string: "http://localhost:55555")!)
        return true
    }

    func applicationDidEnterBackground(application: UIApplication) {
        bgTask = application.beginBackgroundTaskWithExpirationHandler() {
            dispatch_async(dispatch_get_main_queue()) {[unowned self] in
                application.endBackgroundTask(self.bgTask)
                self.bgTask = UIBackgroundTaskInvalid
            }
        }
    }
}

class HTTPServer: RoutingHTTPServer {
    override init() {
        super.init()
        setPort(55555)
        handleMethod("GET", withPath: "/") {
            $1.setHeader("Content-Type", value: "application/x-apple-aspen-config")
            $1.respondWithData(NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("udid", ofType: "mobileconfig")!)!)
        }
        handleMethod("POST", withPath: "/") {
            let raw = NSString(data:$0.body(), encoding:NSISOLatin1StringEncoding) as! String
            let plistString = raw.substringWithRange(Range(start: raw.rangeOfString("<?xml")!.startIndex,end: raw.rangeOfString("</plist>")!.endIndex))
            let plist = NSPropertyListSerialization.propertyListWithData(plistString.dataUsingEncoding(NSISOLatin1StringEncoding)!, options: .allZeros, format: nil, error: nil) as! [String:String]

            let udid = plist["UDID"]! 
            println(udid) // Here is your UDID!

            $1.statusCode = 200
            $1.respondWithString("see https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/ConfigurationProfileExamples/ConfigurationProfileExamples.html")
        }
        start(nil)
    }
}

以下是 udid.mobileconfig 的内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>PayloadContent</key>
        <dict>
            <key>URL</key>
            <string>http://localhost:55555</string>
            <key>DeviceAttributes</key>
            <array>
                <string>IMEI</string>
                <string>UDID</string>
                <string>PRODUCT</string>
                <string>VERSION</string>
                <string>SERIAL</string>
            </array>
        </dict>
        <key>PayloadOrganization</key>
        <string>udid</string>
        <key>PayloadDisplayName</key>
        <string>Get Your UDID</string>
        <key>PayloadVersion</key>
        <integer>1</integer>
        <key>PayloadUUID</key>
        <string>9CF421B3-9853-9999-BC8A-982CBD3C907C</string>
        <key>PayloadIdentifier</key>
        <string>udid</string>
        <key>PayloadDescription</key>
        <string>Install this temporary profile to find and display your current device's UDID. It is automatically removed from device right after you get your UDID.</string>
        <key>PayloadType</key>
        <string>Profile Service</string>
    </dict>
</plist>

配置文件安装将失败(我没有费心实现预期的响应,请参阅 documentation),但应用程序将获得正确的 UDID。您还应该sign the mobileconfig


K
Kumar KL

对于 Swift 3.0,请使用以下代码。

let deviceIdentifier: String = (UIDevice.current.identifierForVendor?.uuidString)!
NSLog("output is : %@", deviceIdentifier)

iOS 11 引入了 DeviceCheck 框架。它具有用于唯一识别设备的完整解决方案。
K
Kumar KL

您可以使用

NSString *sID = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

这对于所有应用中的设备都是独一无二的。


S
Santosh Botre

Apple 在 iOS 11 中添加了一个名为 DeviceCheck 的新框架,它将帮助您非常轻松地获取唯一标识符。阅读此表格以获取更多信息。 https://medium.com/@santoshbotre01/unique-identifier-for-the-ios-devices-590bb778290d


但它需要互联网连接,不是吗?
是的,它需要互联网连接。
k
karim

如果有人在寻找替代方案时偶然发现了这个问题。我在 IDManager 类中采用了这种方法,这是来自不同解决方案的集合。 KeyChainUtil 是一个从钥匙串中读取的包装器。您还可以将 hashed MAC address 用作一种唯一 ID。

/*  Apple confirmed this bug in their system in response to a Technical Support Incident 
    request. They said that identifierForVendor and advertisingIdentifier sometimes 
    returning all zeros can be seen both in development builds and apps downloaded over the 
    air from the App Store. They have no work around and can't say when the problem will be fixed. */
#define kBuggyASIID             @"00000000-0000-0000-0000-000000000000"

+ (NSString *) getUniqueID {
    if (NSClassFromString(@"ASIdentifierManager")) {
        NSString * asiID = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
        if ([asiID compare:kBuggyASIID] == NSOrderedSame) {
            NSLog(@"Error: This device return buggy advertisingIdentifier.");
            return [IDManager getUniqueUUID];
        } else {
            return asiID;
        }

    } else {
        return [IDManager getUniqueUUID];
    }
}


+ (NSString *) getUniqueUUID {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:kBuyassUser andServiceName:kIdOgBetilngService error:&error];
    if (error) {
        NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
        return nil;
    }
    if (!uuid) {
        DLog(@"No UUID found. Creating a new one.");
        uuid = [IDManager GetUUID];
        uuid = [Util md5String:uuid];
        [KeychainUtils storeUsername:USER_NAME andPassword:uuid forServiceName:SERVICE_NAME updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error getting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}

/* NSUUID is after iOS 6. */
+ (NSString *)GetUUID
{
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return [(NSString *)string autorelease];
}

#pragma mark - MAC address
// Return the local MAC addy
// Courtesy of FreeBSD hackers email list
// Last fallback for unique identifier
+ (NSString *) getMACAddress
{
    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("Error: Memory allocation error\n");
        return NULL;
    }

    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2\n");
        free(buf); // Thanks, Remy "Psy" Demerest
        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;
}

+ (NSString *) getHashedMACAddress
{
    NSString * mac = [IDManager getMACAddress];
    return [Util md5String:mac];
}

+ (NSString *)md5String:(NSString *)plainText
{
    if(plainText == nil || [plainText length] == 0)
        return nil;

    const char *value = [plainText 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]];
    }
    NSString * retString = [NSString stringWithString:outputString];
    [outputString release];
    return retString;
}

R
Robert
+ (NSString *) getUniqueUUID {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:kBuyassUser andServiceName:kIdOgBetilngService error:&error];
    if (error) {
    NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
    return nil;
    }
    if (!uuid) {
        DLog(@"No UUID found. Creating a new one.");
        uuid = [IDManager GetUUID];
        uuid = [Util md5String:uuid];
        [KeychainUtils storeUsername:USER_NAME andPassword:uuid forServiceName:SERVICE_NAME updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error getting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}

H
HDdeveloper

我们可以为 ios7 使用 identifierForVendor,

-(NSString*)uniqueIDForDevice
{
    NSString* uniqueIdentifier = nil;
    if( [UIDevice instancesRespondToSelector:@selector(identifierForVendor)] ) { // >=iOS 7
        uniqueIdentifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    } else { //<=iOS6, Use UDID of Device       
            CFUUIDRef uuid = CFUUIDCreate(NULL);
            //uniqueIdentifier = ( NSString*)CFUUIDCreateString(NULL, uuid);- for non- ARC
            uniqueIdentifier = ( NSString*)CFBridgingRelease(CFUUIDCreateString(NULL, uuid));// for ARC
            CFRelease(uuid);
         }
    }
return uniqueIdentifier;
}

- 重要的提示 - -

UDID 和 identifierForVendor 不同:---

1.) On uninstalling  and reinstalling the app identifierForVendor will change.

2.) The value of identifierForVendor remains the same for all the apps installed from the same vendor on the device.

3.) The value of identifierForVendor also changes for all the apps if any of the app (from same vendor) is reinstalled.

你确定吗 ?我们可以为 ios7 使用 identifierForVendor 吗?
C
Community

从 iOS 7 开始,Apple 已经对所有公共 API 隐藏了 UDID。任何以 FFFF 开头的 UDID 都是假 ID。以前工作的“发送 UDID”应用程序不能再用于为测试设备收集 UDID。 (叹!)

当设备连接到 XCode(在管理器中)和设备连接到 iTunes 时,会显示 UDID(尽管您必须单击“序列号”才能显示标识符。

如果您需要获取设备的 UDID 以添加到配置文件中,并且无法在 XCode 中自己完成,则必须引导他们完成从 iTunes 复制/粘贴它的步骤。

Is there a way since (iOS 7's release) to get the UDID without using iTunes on a PC/Mac?


A
Ahmet Kazim Günay

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

    // 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;

K
King-Wizard

一个不完美但最好和最接近 UDID 的替代品之一(在 Swift 中使用 iOS 8.1 和 Xcode 6.1):

生成随机 UUID

let strUUID: String = NSUUID().UUIDString

并使用 KeychainWrapper 库:

将字符串值添加到钥匙串:

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

从钥匙串中检索字符串值:

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

从钥匙串中删除一个字符串值:

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

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


g
garg

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


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅