如何在iOS设备上卸载ios应用程序后在ios中保留identifierForVendor?

我正在开发一个iOS应用程序,该应用程序调用Web服务进行login,并且当时我将login凭证与供应商标识符(identifierForVendor)一起发送到Web服务器,以唯一地标识这些凭证的设备。因此,用户只能拥有一个设备和一个凭证。

我得到了identifierForVendor

NSString *uuid = [[UIDevice currentDevice] identifierForVendor].UUIDString 

这个标识符将存储在networking服务器的数据库中,也存储在设备数据库中。下次用户打开应用程序并尝试从networking服务器下载数据时,首先将用户设备上的本地标识符ForVendor与存储在networking服务器上的标识符进行比较。

用户卸载应用程序并重新安装时发生问题,我发现identifierForVendor已更改。 所以用户不能进一步进行。

我读了苹果文档UIDevice文档

如上所述,如果来自同一供应商的所有应用程序都从设备上卸载,那么在从该供应商新安装任何应用程序时将采用新的标识符ForVendor。

那么在我的情况下如何处理呢?

你可以把它保存在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; } 

一般来说,不要使用identifierForVendor 。 相反,使用NSUUID生成一个自定义的UUID并将其存储在钥匙串中(因为如果应用程序被删除并重新安装,钥匙串不会被删除)。

除了@ nerowolfe的回答 。

SSKeychain使用kSecAttrSynchronizableAny作为默认的同步模式。 你可能不希望identifierForVendor跨多个设备同步,所以这是一个代码:

 // save identifierForVendor in keychain without sync NSError *error = nil; SSKeychainQuery *query = [[SSKeychainQuery alloc] init]; query.service = @"your_service"; query.account = @"your_account"; query.password = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; query.synchronizationMode = SSKeychainQuerySynchronizationModeNo; [query save:&error]; 

您可以尝试使用KeyChain保存您的VendorIdentifier ,即使您卸载了您的应用程序,该设置也将存在直到您的设备被重置。

好。 我不想使用第三方 – 即SSKeychain。 所以这是我试过的代码,相当简单,效果很好:

  NSString *bundleId = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"]; KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:bundleId accessGroup:nil]; if(![keychainItem objectForKey:(__bridge id)(kSecValueData)]){ NSString *idfa = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; [keychainItem setObject:idfa forKey:(__bridge id)(kSecValueData)]; NSLog(@"saving item %@", [keychainItem objectForKey:(__bridge id)(kSecValueData)]); }else{ NSLog(@"saved item is %@", [keychainItem objectForKey:(__bridge id)(kSecValueData)]); } 

Swift版本

 func UUID() -> String { let bundleName = NSBundle.mainBundle().infoDictionary!["CFBundleName"] as! String let accountName = "incoding" var applicationUUID = SAMKeychain.passwordForService(bundleName, account: accountName) if applicationUUID == nil { applicationUUID = UIDevice.currentDevice().identifierForVendor!.UUIDString // Save applicationUUID in keychain without synchronization let query = SAMKeychainQuery() query.service = bundleName query.account = accountName query.password = applicationUUID query.synchronizationMode = SAMKeychainQuerySynchronizationMode.No do { try query.save() } catch let error as NSError { print("SAMKeychainQuery Exception: \(error)") } } return applicationUUID } 

没有确切的方法将一个唯一的号码链接到一个设备,这是不允许的苹果隐私准则。

您可以尝试将您自己的唯一ID保存在钥匙串中,但是如果用户清除其设备,则此ID也不存在。

通常, 将设备链接到用户是错误的,因为您不再识别用户,而是识别设备。 所以你应该改变你的API,以便用户可以重新login,供应商ID绑定到用户帐户。

当用户拥有多个设备(如iPhone和iPad)并在两者上使用您的应用程序时,又会发生什么? 由于您的身份validation是基于唯一的ID,因此无法完成。

我曾经使用KeychainAccess pod来解决这个问题。

在你的pod文件中:

 pod 'KeychainAccess', '~> 2.4' //If you are using Swift 2.3 pod 'KeychainAccess' //Defaults to 3.0.1 which is in Swift 3 

KeychainAccess模块导入您要在钥匙串中设置UUID的文件中

 import KeychainAccess 

使用下面的代码来设置钥匙串中的UUID:

注意: BundleId是关键,UUID是值

 var bundleID = NSBundle.mainBundle().bundleIdentifier var uuidValue = UIDevice.currentDevice().identifierForVendor!.UUIDString //MARK: - setVenderId and getVenderId func setVenderId() { let keychain = Keychain(service: bundleID!) do { try keychain.set(venderId as String, key: bundleID!) print("venderId set : key \(bundleID) and value: \(venderId)") } catch let error { print("Could not save data in Keychain : \(error)") } } func getVenderId() -> String { let keychain = Keychain(service: bundleID!) let token : String = try! keychain.get(bundleID!)! return token }