Как сохранить идентификатор ForVendor в ios после удаления приложения ios на устройстве?
Я разрабатываю приложение для iOS, которое вызывает веб-сервис для входа в систему, и в то же время я отправляю учетные данные для входа на веб-сервер вместе с идентификатором поставщика (identifierForVendor), чтобы идентифицировать устройство уникально для этих учетных данных. Таким образом, у пользователя может быть только одно устройство и одно удостоверение.,
Я получил идентификатор ForVendor с
NSString *uuid = [[UIDevice currentDevice] identifierForVendor].UUIDString
Затем этот идентификатор будет храниться в базе данных веб-сервера, а также в базе данных устройства. В следующий раз, когда пользователь откроет приложение и попытается загрузить данные с веб-сервера, сначала локальный идентификатор ForVendor на устройстве пользователя будет сравниваться с идентификатором, хранящимся на веб-сервере.
Проблема возникает, когда пользователь удаляет приложение и переустанавливает его, я обнаружил, что identifierForVendor изменился. Таким образом, пользователь не может продолжать дальше.
Я читаю яблочную документацию UIDevice Documentation
Как уже упоминалось, если все приложение одного и того же производителя удаляется с устройства, то во время новой установки любого приложения этого поставщика будет использоваться новый идентификатор ForVendor.
Так как с этим бороться в моем случае?
8 ответов
Вы можете сохранить его в 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, который будет существовать до перезагрузки вашего устройства, даже если вы удалите свое приложение.
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
}
Хорошо. Я не хотел использовать третье лицо, а именно 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)]);
}
Нет определенного способа связать уникальный номер с устройством больше, это не разрешено правилами конфиденциальности Apple.
Вы можете попытаться сохранить свой уникальный идентификатор в связке ключей, но если пользователь очистит свое устройство, этот идентификатор также пропадет.
Как правило, неправильно связывать устройство с пользователем, так как вы уже не идентифицируете пользователей, а сами устройства. Поэтому вы должны просто изменить свой API, чтобы пользователь мог повторно войти в систему и чтобы идентификатор поставщика был привязан к учетной записи пользователя.
Кроме того, что происходит, когда пользователь имеет более одного устройства, например iPhone и iPad, и использует ваше приложение на обоих? Поскольку ваша аутентификация основана на уникальном идентификаторе, это не может быть сделано.
Я использовал модуль KeychainAccess для решения этой проблемы.
В вашем файле 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
}