为什么iOS应用更新后会得到一个新的identifierForVendor标识符?

13
每次我的应用程序从App Store更新后,由于某些原因,一小部分用户会获得一个新的identifierForVendor。我的用户不注册或登录。他们都是匿名的,所以我需要通过他们的供应商ID来区分他们。
我考虑过可能是某些设备上空间不足导致应用被删除并重新安装,但这不是问题所在,因为在最近一次更新中,我的一个朋友有超过2GB的空余空间。
我知道如果用户删除并重新安装应用程序,则identifierForVendor将更改。但在这种情况下,应用程序只是更新,并没有被删除和重新安装。
问题可能出在哪里?奇怪的是,开发团队的设备还没有出现这种情况。或者仍然有用户在无数次应用程序更新,操作系统更新等之后没有遇到这个bug。这只发生在少数用户身上。所有用户都是iOS7+,它发生在不同的设备型号和iOS版本上。
我使用下面的代码获取他们的ID:
static let DeviceId = UIDevice.currentDevice().identifierForVendor.UUIDString

然后我将它们保存到NSUserDefaults中:

NSUserDefaults.standardUserDefaults().setBool(true, forKey: "User" + DeviceId)
NSUserDefaults.standardUserDefaults().synchronize()

然后在每次用户登录时检查用户是否存在:

static func doesUserExist() -> Bool {
    var userDefaultValue: AnyObject? = NSUserDefaults.standardUserDefaults().valueForKey("User" + DeviceId)

    if defaultValue == true {
        println("Userdefaults already has this guy, moving on")
        FirstTime = false
        return true
    } else {
        println("First time in the app!")
        FirstTime = true
        return false
    }
}
如果用户存在,它会开始登录过程。如果用户不存在,它将显示注册过程。我正在使用Parse.com作为后端,并将设备ID用作用户名。当这少量用户遇到此错误时,我看到一个新的用户名和一个新帐户被创建。

找到了这个:https://discussions.apple.com/thread/5114517?tstart=0 - Esqarrouth
你曾经发现它为什么会改变吗?我也遇到了同样的问题,人们进行更新后会有不同的供应商ID。 - Mark Molina
但是这些似乎是我目前正在测试的一些可能性:操作系统升级、应用程序缓存存储空间、应用程序更新、用户更改iTunes国家/地区、注册iCloud或新的苹果服务。 - Esqarrouth
嗨@Esq,你找出问题了吗?我也有一种预感,我们的一些用户的identifierForVendor被更改了。谢谢。希望你看到我的评论。 :) - KarenAnne
不,我不知道问题出在哪里,但是 https://github.com/soffes/sskeychain 可以帮助解决它。 - Esqarrouth
这里也有相同的问题,除了几乎所有用户的供应商ID在更新中都发生了变化。(而不是所有更新)看起来像是API的bug,因为开发者信息没有任何改变。 - MasterBeta
3个回答

7

在5月至7月期间,更新应用程序商店中的应用程序时,存在一个影响identifierForVendor计算的错误。苹果声称他们已经解决了这个问题,并且推送另一个更新应该可以在关键日期之前恢复原始值。 参考:https://openradar.appspot.com/22677034

请注意,即使在7月之后几周更新,一些用户仍然观察到了这个问题。因此,对于某些用户来说,这个错误仍然存在,或者它可能在未来的任何时候重新出现。因此,如果您将此数据用作加密的一部分,则最好将其保存到钥匙串中。


0

将vendorID保存在KeyChain中,这样即使删除或更新后也会持久存在。

-(NSString *)getUniqueDeviceIdentifierAsString
{

NSString *appName=[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey];

NSString *strApplicationUUID = [SSKeychain passwordForService:appName account:@"incoding"];
if (strApplicationUUID == nil)
{
    strApplicationUUID  = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    [SSKeychain setPassword:strApplicationUUID forService:appName account:@"incoding"];
}

return strApplicationUUID;
}

免责声明:我在一段时间前从其他SO答案中获取了这段代码,所以我不记得要表扬谁,但最终这不是我的功劳。@Jonny找到了source

2
谢谢你提供的代码。它将有助于解决这个问题。然而,这篇文章更关注问题可能出在哪里,而不是解决方案。 - Esqarrouth
1
如在此答案的评论中提到:https://dev59.com/emEh5IYBdhLWcg3w6HEG#21878670,使用 iCloud 同步钥匙串会破坏它。 - Jonny
@Jonny:你可以通过向密钥添加一些设备信息来解决这个问题。但对于这里的问题,这并不是必要的,因为它只涉及到识别用户 - 我怀疑有很多用户会共享他们的iCloud... - dogsgod
2
如果您在保存到钥匙串时使用本地安全框架,则有一个属性可以使钥匙串项仅对设备可访问。也就是说,它不会同步到iTunes或iCloud。您可以将此值添加到您的属性中:CFDictionaryAddValue(attributes,kSecAttrAccessible,kSecAttrAccessibleWhenUnlockedThisDeviceOnly) - chalcopyrite
我正在iOS11上进行测试,即使我明确地卸载并重新安装应用程序,相同的identifierForVendor仍然被返回。我需要等待一天看看这是否会在更长的时间内持续发生。(测试了3次卸载和重新安装:每次都是相同的ID)。无论是使用Xcode管理的侧载还是使用开发人员配置文件签名的自定义构建,都会出现此问题。尚未测试发布签名的构建。实际上,我们需要一个唯一的标识符,因此我们将采用密钥链和UUID来解决。 - FranticRock

0
我不明白为什么你先将IFV保存到NSUserDefaults中,然后再检查该键是否存在。我认为你应该:
1)首先检查NSUserDefaults,看看你创建的IFV键是否存在;
2)如果NSUserDefaults键存在,那么就可以对其进行操作,因为该用户的个人资料已经存在;
3)如果键不存在,则获取IFV并将其保存到NSUserDefaults中。
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

if ([defaults valueForKey:@"IFV"]) {
    //this user already exists, do what you need to do next with IFV
}

else{
    //this is their first time using the app
    NSString *ifvString = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    [defaults setValue:ifvString forKey:@"IFV"];

    //do what you need to do next with IFV
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接