简体   繁体   English

卸载设备上的ios应用后,如何在ios中保留identifierForVendor?

[英]How to preserve identifierForVendor in ios after uninstalling ios app on device?

I am developing an iOS app which calls web-service for login and at that time i send login credentials to web server along with vendor identifier (identifierForVendor),to identify device uniquely for those credentials.So user can have only one device and one credential. 我正在开发一个iOS应用程序,该应用程序调用Web服务进行登录,当时我将登录凭据与供应商标识符(identifierForVendor)发送到Web服务器,以唯一地标识用于这些凭据的设备,因此用户只能拥有一个设备和一个凭据。 。

I got identifierForVendor with 我得到了identifierForVendor

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

This identifier will then store in database of web server and also in device database.Next time when user opens application and will try to download data from web server firstly local identifierForVendor on users device will compare with identifier stored on web server. 然后,该标识符将存储在Web服务器的数据库以及设备数据库中。下次用户打开应用程序并尝试从Web服务器下载数据时,首先将用户设备上的本地identifierForVendor与Web服务器上存储的标识符进行比较。

Problem occurs when user uninstall app and reinstall it, I found that identifierForVendor is changed. 当用户卸载应用程序并重新安装它时,出现问题,我发现identifierForVendor已更改。 So user cannot proceed further. 因此用户无法继续进行。

I read apple documentation UIDevice Documentation 我阅读了苹果文档UIDevice文档

As mention there, if all app from same vendor uninstalls from device then at time of new installation of any app from that vendor will take new identifierForVendor. 如此处所述,如果来自同一供应商的所有应用都从设备上卸载,那么在新安装该供应商的任何应用时,它将采用新的identifierForVendor。

So how to deal with this in my case ? 那么我该如何处理呢?

You may keep it in KeyChain 您可以将其保存在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;
}

Generally, don't use identifierForVendor . 通常,不要使用identifierForVendor Instead, use NSUUID to generate a custom UUID and store that in the keychain (because the keychain isn't deleted if the app is deleted and reinstalled). 而是使用NSUUID生成自定义UUID并将其存储在钥匙串中(因为如果删除并重新安装该应用程序,则不会删除钥匙串)。

Addition to @nerowolfe's answer . 除了@nerowolfe的答案

SSKeychain uses kSecAttrSynchronizableAny as a default synchronization mode. SSKeychain使用kSecAttrSynchronizableAny作为默认同步模式。 You probably don't want identifierForVendor to be synced across multiple devices so here is a code: 您可能不希望将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 ,即使您卸载应用程序,它也将一直存在直到重置设备为止。

Ok. 好。 I didn't want to use a third party - namely SSKeychain. 我不想使用第三方-即SSKeychain。 So this is the code I tried, fairly simple and works well: 因此,这是我尝试过的代码,相当简单并且运行良好:

    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 version 迅捷版

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
}

There is no definite way to link a unique number to a device any more, this is not allowed with the Apple privacy guidelines. 再也没有确定的方法将唯一编号链接到设备,这是Apple隐私准则所不允许的。

You can try to save your own Unique ID in the keychain, but if the user clear his device this ID is also gone. 您可以尝试在钥匙串中保存自己的唯一ID,但是如果用户清除了他的设备,该ID也将消失。

Generally is it just wrong to link a device to a user , since you are not longer identifying users but devices. 通常, 将设备链接到用户是不对的,因为您不再标识用户而是设备。 So you should just change your API so that the user can re-login and that the vendor ID is bound to the users account. 因此,您只需要更改您的API,以便用户可以重新登录并将供应商ID绑定到用户帐户。

Also what happens when the user has more then one device, like an iPhone and iPad, and uses you app on both? 当用户拥有一部以上的设备(例如iPhone和iPad)并在两者上使用您的应用程序时,还会发生什么? Since you authentication is based an unique ID this can not be done. 由于您的身份验证基于唯一的ID,因此无法完成。

I had used KeychainAccess pod for this problem. 我曾使用KeychainAccess吊舱解决此问题。

In your pod file : 在您的pod文件中:

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

Import KeychainAccess module in file where you want to set UUID in keychain KeychainAccess模块导入要在其中设置UUID的文件中

import KeychainAccess

Use below code to set and get UUID from keychain : 使用以下代码设置并从钥匙串获取UUID:

Note : BundleId is key and UUID is value 注意: 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
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM