How to preserve identifierForVendor in ios after uninstalling ios app on device?
我正在开发一个iOS应用程序,它调用web服务进行登录,然后我将登录凭据与供应商标识符(identifierForVendor)一起发送到Web服务器,以便为这些凭证唯一地标识设备。因此用户只能拥有一个设备和一个凭证。
我有了identifierForVendor
1 | NSString *uuid = [[UIDevice currentDevice] identifierForVendor].UUIDString |
然后该标识符将存储在Web服务器的数据库中以及设备数据库中。当用户打开应用程序并尝试从Web服务器下载数据时,用户设备上的本地identifierForVendor将与存储在Web服务器上的标识符进行比较。
用户卸载应用程序并重新安装时出现问题,我发现identifierForVendor已更改。因此用户无法继续前进。
我阅读了苹果文档UIDevice Documentation
如前所述,如果来自同一供应商的所有应用程序从设备卸载,则在从该供应商新安装任何应用程序时将采用新的identifierForVendor。
那么在我的案例中如何处理这个问题呢?
您可以将其保存在KeyChain中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | -(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; } |
通常,不要使用
除了@ nerowolfe的回答。
SSKeychain使用
1 2 3 4 5 6 7 8 | // 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。所以这是我试过的代码,非常简单并且效果很好:
1 2 3 4 5 6 7 8 9 10 | 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版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 } |
没有明确的方法可以将唯一号码链接到设备,Apple隐私准则不允许这样做。
您可以尝试在钥匙串中保存自己的唯一ID,但如果用户清除了他的设备,则此ID也会消失。
通常,将设备链接到用户是错误的,因为您不再识别用户而是设备。因此,您应该只更改API,以便用户可以重新登录,并且供应商ID绑定到用户帐户。
当用户拥有多个设备(如iPhone和iPad)并在两者上使用应用程序时会发生什么?由于您的身份验证基于唯一ID,因此无法执行此操作。
我曾经使用过KeychainAccess pod来解决这个问题。
在您的pod文件中:
1 2 | pod 'KeychainAccess', '~> 2.4' //If you are using Swift 2.3 pod 'KeychainAccess' //Defaults to 3.0.1 which is in Swift 3 |
在要在密钥链中设置UUID的文件中导入
1 | import KeychainAccess |
使用以下代码设置并从钥匙串获取UUID:
注意:BundleId是键,UUID是值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 } |