卸载 ios 应用程序后,如何在 ios 中保存 IdentifierForVendor?

我正在开发一个 iOS 应用程序,它调用网络服务登录,当时我发送登录凭证到网络服务器连同供应商标识符(IdentifierForVendor) ,以确定这些凭证唯一的设备。所以用户只能有一个设备和一个凭证。

我有供应商的身份证明

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

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

当用户卸载并重新安装应用程序时,我发现 IdentifierForVendor 已经更改,因此用户无法继续进行操作。

我读过苹果的文档 UIDDevice 文档

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

那我该怎么办呢?

56727 次浏览

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

您可以尝试使用 钥匙链保存您的 供应商标识符,这将存在,直到您的设备是重置,即使您卸载您的应用程序。

你可以把它放在钥匙链里

-(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;
}

现在已经没有明确的方法可以将一个唯一的数字链接到一个设备上,这是苹果隐私指南所不允许的。

您可以尝试在密钥链中保存您自己的 Unique ID,但是如果用户清除了他的设备,这个 ID 也会消失。

一般来说,将设备连接到用户只是错误的,因为您不再识别用户,而是识别设备。因此,您只需更改您的 API,以便用户可以重新登录,并且供应商 ID 绑定到用户帐户。

还有,当用户拥有一个以上的设备(如 iPhone 和 iPad) ,并在两者上都使用你的应用程序时,会发生什么情况?由于您的身份验证基于唯一的 ID,所以这是不可能的。

好吧。我不想使用第三方-即 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)]);
}

附加到@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];

快速版

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
}

我用 钥匙链访问豆荚来解决这个问题。

在你的逃生舱文件里:

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

在要在 keychain 中设置 UUID 的文件中导入 KeychainAccess模块

import KeychainAccess

使用下面的代码设置并从 keychain 获取 UUID:

注意: < em > BundleId 是 key,UUID 是 value

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
}