UIDevice uniqueIdentifier устарел - что теперь делать?

501

Только что стало известно, что свойство UIDevice uniqueIdentifier устарело в iOS 5 и недоступно в iOS 7 и выше. Никакой альтернативный метод или свойство, кажется, не доступно или не ожидается.

Многие из наших существующих приложений сильно зависят от этого свойства для уникальной идентификации конкретного устройства. Как мы можем решить эту проблему в будущем?

Предложение из документации в 2011-2012 было:

Особые соображения

Не используйте свойство uniqueIdentifier. Чтобы создать уникальный идентификатор, специфичный для вашего приложения, вы можете вызвать CFUUIDCreateфункцию для создания UUIDи записать его в базу данных по умолчанию, используя NSUserDefaultsкласс.

Однако это значение не будет таким же, если пользователь удаляет и переустанавливает приложение.

Оливер Пирмейн
источник
1
Для приложений, все еще использующих uniqueIdentifier, iOS7 теперь возвращает FFFFFFFF + identifierForVendor, который ломает множество плохо написанных невозобновляемых приложений подписки.
Ритмичный кулак
Если, к счастью, ваше приложение использует Push-уведомления, вы можете использовать токен, отправленный из службы push-уведомлений Apple, он также уникален для каждого устройства
Calin Chitu
@CalinChitu Если пользователь не принимает push-уведомления, вы все еще получаете pushID для этого пользователя?
Чейз Робертс

Ответы:

272

UUID, созданный пользователем CFUUIDCreate , уникален, если пользователь удаляет и переустанавливает приложение: вы будете получать новый каждый раз.

Но вы можете захотеть, чтобы он не был уникальным, то есть он должен оставаться таким же, когда пользователь удаляет и переустанавливает приложение. Это требует немного усилий, так как наиболее надежным идентификатором для каждого устройства является MAC-адрес. Вы можете запросить MAC и использовать его в качестве UUID.

Редактировать: Конечно, нужно всегда запрашивать MAC одного и того же интерфейса. Я думаю, что лучшая ставка с en0. MAC всегда присутствует, даже если интерфейс не имеет IP / не работает.

Редактировать 2: Как указывали другие, предпочтительное решение, так как iOS 6 - это [UIDevice identifierForVendor] . В большинстве случаев вы должны иметь возможность использовать его в качестве замены старого -[UIDevice uniqueIdentifier](но UUID, который создается при первом запуске приложения, - это то, что Apple, похоже, хочет, чтобы вы использовали).

Редактировать 3: Таким образом, этот важный момент не теряется в шуме комментариев: не используйте MAC в качестве UUID, создайте хэш с использованием MAC . Этот хеш всегда будет создавать один и тот же результат каждый раз, даже при переустановках и приложениях (если хеширование выполняется одинаково). В любом случае, в настоящее время (2013 г.) в этом больше нет необходимости, если только вам не нужен «стабильный» идентификатор устройства на iOS <6.0.

Редактировать 4: В iOS 7 Apple теперь всегда возвращает фиксированное значение при запросе MAC, чтобы специально помешать MAC в качестве основы для схемы ID . Так что теперь вы действительно должны использовать - [UIDevice identifierForVendor] или создать UUID для каждой установки.

DarkDust
источник
8
Mac-адрес не меняется в зависимости от того, подключен ли пользователь через Wi-Fi или нет?
Оливер Пирмен
1
@DarkDust: но поскольку активный интерфейс изменяется при переключении с Wi-Fi на сотовый модем, MAC-адрес активного интерфейса также должен измениться; если вы не всегда выбираете конкретный интерфейс для получения MAC
user102008
3
@ Роджер Нолан: Пожалуйста, не редактируйте ответы других людей и не добавляйте материалы, которые выглядят так, как будто исходили от оригинального автора. Спасибо.
DarkDust
2
@RogerNolan Пока пост не является ответом сообщества, изменения предназначены для исправления ошибок и подобных вещей, а не для добавления новых материалов. Есть причина, по которой вы получили эту привилегию. Представьте, что я отредактирую ваш ответ и напишу немного BS, люди подумают, что вы написали бы это. Я сомневаюсь, что вам это понравится :-) Но вы не получаете уведомления о том, что редактирование произошло, я узнал об этом только случайно.
DarkDust
3
Apple теперь отвергает приложения, использующие хешированный MAC.
Идан,
91

Вы можете использовать свой вариант для Apple UDIDуже. Добрый парень gekitz написал категорию, по UIDeviceкоторой будет генерироваться некая UDIDоснованная на mac-адресе устройства и идентификаторе пакета.

Вы можете найти код на GitHub

Сергей Мамонтов
источник
3
Эта реализация является уникальной (MAC-адрес) для устройства после переустановки, например, UniqueId Apple, но также уважает конфиденциальность, будучи уникальной для приложения (также используйте bundleId) ... Должно быть, imho, что Apple должна включить в свои API. .. вместо того, чтобы осудить без каких-либо альтернатив.
Винсент Гверчи
8
Хотя он использует лицензию BSD старого стиля с пунктом о рекламе, гадость.
jbtule
8
Для тех, кто сейчас находит этот пост, лицензия была изменена с момента вышеупомянутого комментария jbtule.
Джеймс
1
Как уже говорилось в комментарии к коммиту, библиотека «как есть» создает серьезную проблему утечки конфиденциальности и не должна использоваться:
Будет ли
15
Начиная с iOS 7, система всегда возвращает значение, 02:00:00:00:00:00когда вы запрашиваете MAC-адрес на любом устройстве. Проверьте здесь: developer.apple.com/library/prerelease/ios/releasenotes/General/…
Hejazi
61

Основываясь на ссылке, предложенной @moonlight, я провел несколько тестов, и, похоже, это лучшее решение. Как говорит @DarkDust, метод проверяет, en0который всегда доступен.
Есть 2 варианта:
uniqueDeviceIdentifier(MD5 MAC + CFBundleIdentifier)
и uniqueGlobalDeviceIdentifier(MD5 MAC), они всегда возвращают одинаковые значения.
Ниже тесты, которые я сделал (с реальным устройством):

#import "UIDevice+IdentifierAddition.h"

NSLog(@"%@",[[UIDevice currentDevice] uniqueDeviceIdentifier]);
NSLog(@"%@",[[UIDevice currentDevice] uniqueGlobalDeviceIdentifier]);

XXXX21f1f19edff198e2a2356bf4XXXX - (WIFI) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (WIFI) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (3G) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (3G) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (GPRS) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (GPRS) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (режим AirPlane) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (режим AirPlane) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (Wi-Fi) после удаления и переустановки приложения XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) после удаления и установки приложения

Надеюсь, это полезно.

РЕДАКТИРОВАТЬ:
Как отмечали другие, это решение в iOS 7 больше не полезно, так uniqueIdentifierкак больше не доступно, и запрос на MAC-адрес теперь возвращает всегда 02: 00: 00: 00: 00: 00

Мат
источник
13
это не будет работать на iOS7, Apple исключает использование MAC-адреса.
Сарим Сидд
@SarimSidd На данный момент информация о iOS 7 находится под NDA, мы не можем обсуждать здесь.
Мат
57

Проверь это,

мы можем использовать связку ключей вместо NSUserDefaultsкласса, чтобы хранить UUIDсозданные CFUUIDCreate.

таким образом, мы могли бы избежать UUIDповторного использования для восстановления и получать всегда одно и то же UUIDдля одного и того же приложения, даже если пользователь удалял и переустанавливал снова.

UUID будет воссоздан только при сбросе устройства пользователем.

Я попробовал этот метод с SFHFKeychainUtils, и он работает как шарм.

ytur
источник
33
Этот метод является надежной заменой UDID. Это также имеет дополнительное преимущество - воссоздание идентификатора по формату устройства (например, если устройство меняет владельца). Однако важно отметить, что цепочку для ключей можно восстановить на другие устройства, если пользователь зашифрует их резервную копию. Это может привести к ситуации, когда несколько устройств используют один и тот же UUID. Чтобы избежать этого, установите доступность вашего элемента цепочки для ключей в kSecAttrAccessibleAlwaysThisDeviceOnly. Это гарантирует, что ваш UUID не будет перенесен на любое другое устройство. Чтобы получить доступ к вашему UUID из других приложений, используйте kSecAttrAccessGroupключ.
Дживан Тахар
Где именно (какой ключ) вы должны использовать для хранения UUID в связке ключей?
lostintranslation
Opps! ссылка не работает
COVID19
48

Создайте свой собственный UUID и сохраните его в связке ключей. Таким образом, оно сохраняется даже при удалении вашего приложения. Во многих случаях это также сохраняется, даже если пользователь мигрирует между устройствами (например, полное резервное копирование и восстановление на другое устройство).

По сути, он становится уникальным идентификатором пользователя, насколько вам известно. (даже лучше, чем идентификатор устройства ).

Пример:

Я определяю пользовательский метод для создания UUIDкак:

- (NSString *)createNewUUID 
{
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return [(NSString *)string autorelease];
}

Вы можете сохранить его KEYCHAINпри первом запуске вашего приложения. Так что после первого запуска мы можем просто использовать его из цепочки для ключей, не нужно его восстанавливать. Основная причина использования связки ключей для хранения: Когда вы установите UUIDсвязку ключей, она сохранится, даже если пользователь полностью удалит приложение, а затем снова установит его. , Таким образом, это постоянный способ его хранения, а это значит, что ключ будет уникальным во всех отношениях.

     #import "SSKeychain.h"
     #import <Security/Security.h>

При запуске приложения включите следующий код:

 // getting the unique key (if present ) from keychain , assuming "your app identifier" as a key
       NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];
      if (retrieveuuid == nil) { // if this is the first time app lunching , create key for device
        NSString *uuid  = [self createNewUUID];
// save newly created key to Keychain
        [SSKeychain setPassword:uuid forService:@"your app identifier" account:@"user"];
// this is the one time process
}

Загрузите файлы SSKeychain.m и .h из sskeychain и перетащите файлы SSKeychain.m и .h в свой проект и добавьте «Security.framework» в свой проект. Чтобы использовать UUID впоследствии просто используйте:

NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];
Самир Джварчан
источник
Потому что идентификаторForVendor работает не идеально. В некоторых случаях может вернуть ноль или 0x0. Этот метод, кажется, работает отлично
CReaTuS
3
Кто-нибудь подтвердил, что это работает на iOS7 после цикла удаления / повторной установки + подтвержденной отправки приложения Apple?
mindbomb
Я начал использовать это решение. Несколько тестов на 2 устройствах (перестройка, переустановка, выключение устройства) показали, что идентификатор одинаков. iOS 10.3.
Deko
16

Возможно, вы можете использовать:

[UIDevice currentDevice].identifierForVendor.UUIDString

Документация Apple описывает идентификатор ForVender следующим образом:

Значение этого свойства одинаково для приложений от одного поставщика, работающих на одном устройстве. Разное значение возвращается для приложений на одном устройстве от разных поставщиков и для приложений на разных устройствах независимо от поставщика.

diadyne
источник
Любопытно, почему никто не поднял это до недавнего времени ... И теперь я вижу, что это ново с iOS 6.
Джеймс Бутчер
1
Если пользователь обновит ios и / или установит новый ios, тогда значение identifierForVendor изменится или останется таким же?
Сунил Залавадия
1
После удаления всех приложений от одного поставщика это значение будет изменено.
Митеш Хатри,
14

Вы можете рассмотреть вопрос об использовании, OpenUDIDкоторый является заменой устаревших UDID.

В основном для соответствия UDIDтребуются следующие функции:

  1. уникальный или достаточно уникальный (столкновение с низкой вероятностью, вероятно, очень приемлемо)
  2. постоянство при перезагрузках, восстанавливает, удаляет
  3. доступно в приложениях разных поставщиков (полезно для привлечения пользователей через сети CPI) -

OpenUDID выполняет вышеуказанное и даже имеет встроенный механизм отказа для дальнейшего рассмотрения.

Проверьте http://OpenUDID.org это указывает на соответствующий GitHub. Надеюсь это поможет!

Как примечание, я бы уклонялся от любой альтернативы MAC-адреса. Хотя MAC-адрес выглядит как заманчивое и универсальное решение, убедитесь, что этот низко висящий фрукт отравлен. MAC-адрес очень чувствителен, и Apple вполне может отказаться от доступа к нему, прежде чем вы даже скажете «ОТПРАВИТЬ ЭТО ПРИЛОЖЕНИЕ» ... сетевой адрес MAC используется для проверки подлинности определенных устройств на частных каналах (WLAN) или других виртуальных частных сети (VPN). .. это даже более чувствительно, чем прежний UDID!

ylechelle
источник
Мне действительно интересно, как это работает? Код написан на Objective-C, но нет другого хорошего решения, которое бы соответствовало вышеуказанным требованиям, так что же отличает этот фреймворк? Решение, которое использует этот фреймворк, также можно публиковать в качестве предлагаемого ответа здесь ...
jake_hetfield
Я согласен - MAC-адрес также можно настроить вручную («клонировать»), хотя по большей части он маловероятен. Я должен протестовать против D в UDID. Это не идентификатор устройства, это UUID (универсальный уникальный идентификатор). Идентификатор устройства проштампован Apple с завода на каждом устройстве в ПЗУ.
Джей Имерман
Лучшее решение для iOS7 также делает то, что действительно нужно для уникальной идентификации устройства
vishal dharankar
1
OpenUDID устарела и не рекомендуется использовать
mkll
11

Я уверен, что Apple раздражала многих людей этим изменением. Я разрабатываю бухгалтерское приложение для iOS и имею онлайн-сервис для синхронизации изменений, сделанных на разных устройствах. Служба поддерживает базу данных всех устройств и изменений, которые необходимо распространить на них. Поэтому важно знать, какие устройства какие. Я отслеживаю устройства, использующие UIDevice uniqueIdentifier, и за то, что оно того стоит, вот мои мысли.

  • Создать UUID и сохранить в пользовательских настройках по умолчанию? Ничего хорошего, потому что это не сохраняется, когда пользователь удаляет приложение. Если они позже установятся снова, онлайн-сервис не должен создавать новую запись устройства, что приведет к потере ресурсов на сервере и выдаче списка устройств, содержащих одно и то же, два или более раз. Пользователи увидят более одного «iPhone Боба» в списке, если они переустановят приложение.

  • Создать UUID и сохранить в цепочке для ключей? Это был мой план, поскольку он сохраняется даже при удалении приложения. Но при восстановлении резервной копии iTunes на новое устройство iOS цепочка для ключей передается, если резервная копия зашифрована. Это может привести к тому, что два устройства будут содержать один и тот же идентификатор устройства, если и старое, и новое устройства находятся в эксплуатации. Они должны быть указаны как два устройства в онлайн-сервисе, даже если имя устройства совпадает.

  • Сгенерировать хеш MAC-адрес и идентификатор пакета? Это выглядит как лучшее решение для того, что мне нужно. Хэшируя с идентификатором пакета, сгенерированный идентификатор устройства не позволяет отслеживать устройство между приложениями, и я получаю уникальный идентификатор для комбинации приложение + устройство.

Интересно отметить, что собственная документация Apple относится к проверке квитанций Mac App Store путем вычисления хэша системного MAC-адреса, а также идентификатора и версии пакета. Так что это кажется допустимым политикой, независимо от того, проходит ли это через проверку приложения, я пока не знаю.

Мэтью Уотерс
источник
10
Чтобы избежать ситуации, описанной во втором пункте, установите доступность элемента цепочки для ключей на kSecAttrAccessibleAlwaysThisDeviceOnly. Это гарантирует, что ваш UUID не восстановится на других устройствах, даже если резервная копия зашифрована.
Дживан Тахар
Это действительно поведение, которое я видел много раз. Например, я регистрирую свой iPhone для Google Sync. Затем я получил новый iPhone, зарегистрировал его и вуаля - теперь у меня в списке настроек синхронизации есть 2 iPhone.
Джей Имерман
11

Похоже на iOS 6, Apple рекомендует использовать класс NSUUID .

Из сообщения теперь в документах UIDevice для uniqueIdentifierсвойства:

Устаревший в iOS 5.0. Вместо этого, при необходимости, используйте свойство identifierForVendor этого класса или свойство advertisingIdentifier класса ASIdentifierManager, либо используйте метод UUID класса NSUUID, чтобы создать UUID и записать его в пользовательскую базу данных по умолчанию.

Nate
источник
10

Может помочь: используйте приведенный ниже код, он всегда будет уникальным, кроме случаев, когда вы стираете (форматируете) свое устройство.

UIDevice *myDevice=[UIDevice currentDevice];
NSString *UUID = [[myDevice identifierForVendor] UUIDString];
Ашвин Аджадия
источник
1
Я использовал этот код. Но когда я удалил приложение и снова установил, я получил новый идентификатор
Durgaprasad
1
Это простое решение, если вам не нужен надежный метод. Я использую его в своем приложении сейчас.
Рувим Л.
@Durgaprasad: он всегда будет меняться, потому что зависит от поставщика. Например: 1. Если у вас установлено приложение с bundleidenedifier: com.abcd.com =>, тогда оно изменится. 2. Если у вас установлено два приложения с bundleidenedifier: com.abcd.com => Тогда оно не изменится (сохраните одно приложение во время)
Ашвин Аджадия
7

Я хотел бы также предложить переход от uniqueIdentifierк этой открытой исходной библиотеке (2 простых категории действительно) , которые используют устройство MAC - адрес вместе с Bundle Identifier App генерировать уникальный идентификатор в приложениях , которые могут быть использованы в качестве замены UDID.

Имейте в виду, что в отличие от UDID это число будет различным для каждого приложения.

Вам просто нужно импортировать включенные NSStringи UIDeviceкатегории и звонить [[UIDevice currentDevice] uniqueDeviceIdentifier]так:

#import "UIDevice+IdentifierAddition.h"
#import "NSString+MD5Addition.h"
NSString *iosFiveUDID = [[UIDevice currentDevice] uniqueDeviceIdentifier]

Вы можете найти его на Github здесь:

UIDevice с UniqueIdentifier для iOS 5


Вот категории (только файлы .m - проверьте заголовки в проекте github):

UIDevice + IdentifierAddition.m

#import "UIDevice+IdentifierAddition.h"
#import "NSString+MD5Addition.h"

#include <sys/socket.h> // Per msqr
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>

@interface UIDevice(Private)

- (NSString *) macaddress;

@end

@implementation UIDevice (IdentifierAddition)

////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Private Methods

// Return the local MAC addy
// Courtesy of FreeBSD hackers email list
// Accidentally munged during previous update. Fixed thanks to erica sadun & mlamb.
- (NSString *) macaddress{
    
    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;
    
    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;
    
    if ((mib[5] = if_nametoindex("en0")) == 0) {
        printf("Error: if_nametoindex error\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }
    
    if ((buf = malloc(len)) == NULL) {
        printf("Could not allocate memory. error!\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2");
        return NULL;
    }
    
    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 
                           *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
    free(buf);
    
    return outstring;
}

////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Public Methods

- (NSString *) uniqueDeviceIdentifier{
    NSString *macaddress = [[UIDevice currentDevice] macaddress];
    NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];  
    NSString *stringToHash = [NSString stringWithFormat:@"%@%@",macaddress,bundleIdentifier];
    NSString *uniqueIdentifier = [stringToHash stringFromMD5];  
    return uniqueIdentifier;
}

- (NSString *) uniqueGlobalDeviceIdentifier{
    NSString *macaddress = [[UIDevice currentDevice] macaddress];
    NSString *uniqueIdentifier = [macaddress stringFromMD5];    
    return uniqueIdentifier;
}

@end

NSString + MD5Addition.m:

#import "NSString+MD5Addition.h"
#import <CommonCrypto/CommonDigest.h>

@implementation NSString(MD5Addition)

- (NSString *) stringFromMD5{
    
    if(self == nil || [self length] == 0)
        return nil;
    
    const char *value = [self UTF8String];
    
    unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5(value, strlen(value), outputBuffer);
    
    NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
        [outputString appendFormat:@"%02x",outputBuffer[count]];
    }
    return [outputString autorelease];
}

@end
Чаун
источник
3
Начиная с iOS 7, Apple будет возвращать постоянное значение для MAC-адреса. Это имеет смысл. MAC-адрес чувствителен.
Роберто
4

MAC-адрес может быть подделан, что делает такой подход бесполезным для привязки контента к конкретным пользователям или реализации функций безопасности, таких как черные списки.

После некоторых дальнейших исследований мне кажется, что на данный момент мы остались без надлежащей альтернативы. Я серьезно надеюсь, что Apple пересмотрит свое решение.

Возможно, было бы неплохо написать Apple по этой теме и / или подать запрос об ошибке / возможности по этому вопросу, поскольку, возможно, они даже не знают о полных последствиях для разработчиков.

Toastor
источник
13
Тем не менее, я считаю, что UUID также может быть подделан / взломан на взломанном телефоне, поэтому технически существующий [UIDevice uniqueIdentifier] такой же недостаток.
Оливер Пирмен
3
Вы всегда можете создать идентификатор на сервере и сохранить его на устройстве. Вот как большинство приложений делают это. Я не понимаю, зачем программистам на iOS нужно что-то особенное.
Sulthan
1
@Sulthan не работает на iOS, потому что, если вы удалите приложение, все его данные исчезнут, поэтому невозможно гарантировать такой уникальный идентификатор устройства.
lkraider
4
Нет, если вы сохраните его в связку ключей. Во всяком случае, я никогда не видел приложение, где это было проблемой. Если приложение и данные были удалены, вам не нужен один и тот же идентификатор устройства. Если вы хотите идентифицировать пользователя, спросите его по электронной почте.
Sulthan
Доступ к MAC-адресам также был запрещен Apple в новом выпуске iOS;
От
4

UIDevice identifierForVendor Представленный в iOS 6 будет работать для ваших целей.

identifierForVendorпредставляет собой буквенно-цифровую строку, которая однозначно идентифицирует устройство поставщика приложения. (Только для чтения)

@property(nonatomic, readonly, retain) NSUUID *identifierForVendor

Значение этого свойства одинаково для приложений от одного поставщика, работающих на одном устройстве. Различное значение возвращается для приложений на одном устройстве от разных поставщиков и для приложений на разных устройствах в зависимости от поставщика.

Доступный в iOS 6.0 и позже и объявленный в UIDevice.h

Для iOS 5 обратитесь к этой ссылке UIDevice-with-UniqueIdentifier-for-iOS-5

Махендра Лия
источник
4

Используя SSKeychain и код, упомянутый выше. Вот код для копирования / вставки (добавьте модуль SSKeychain):

+(NSString *) getUUID {

//Use the bundle name as the App identifier. No need to get the localized version.

NSString *Appname = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];    

//Check if we have UUID already

NSString *retrieveuuid = [SSKeychain passwordForService:Appname account:@"user"];

if (retrieveuuid == NULL)
{

    //Create new key for this app/device

    CFUUIDRef newUniqueId = CFUUIDCreate(kCFAllocatorDefault);

    retrieveuuid = (__bridge_transfer NSString*)CFUUIDCreateString(kCFAllocatorDefault, newUniqueId);

    CFRelease(newUniqueId);

    //Save key to Keychain
    [SSKeychain setPassword:retrieveuuid forService:Appname account:@"user"];
}

return retrieveuuid;

}

Komposr
источник
3

Следующий код помогает получить UDID:

        udid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
        NSLog(@"UDID : %@", udid);
santify
источник
3

Это код, который я использую, чтобы получить идентификатор для iOS 5 и iOS 6, 7:

- (NSString *) advertisingIdentifier
{
    if (!NSClassFromString(@"ASIdentifierManager")) {
        SEL selector = NSSelectorFromString(@"uniqueIdentifier");
        if ([[UIDevice currentDevice] respondsToSelector:selector]) {
            return [[UIDevice currentDevice] performSelector:selector];
        }
    }
    return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}
Гжегож Круковски
источник
Что вы делаете с предупреждением компилятора PerformSelector may cause a leak because its selector is unknown?
Базилик Бурк
Вы больше не можете использовать AdvertisingIdentifier для этой цели, так как Apple отклонит его. Больше информации: techcrunch.com/2014/02/03/…
codeplasma
2

iOS 11 представила инфраструктуру DeviceCheck. Он имеет полностью защищенное решение для уникальной идентификации устройства.

Сантош Ботре
источник
1

Рабочий способ получить UDID:

  1. Запустите веб-сервер внутри приложения с двумя страницами: одна должна возвращать специально созданный профиль MobileConfiguration, а другая должна собирать UDID. Больше информации здесь , здесь и здесь .
  2. Вы открываете первую страницу в Mobile Safari из приложения, и она перенаправляет вас на Settings.app с просьбой установить профиль конфигурации. После установки профиля UDID отправляется на вторую веб-страницу, и вы можете получить к нему доступ из приложения. (Settings.app имеет все необходимые права и различные правила песочницы).

Пример использования RoutingHTTPServer :

import UIKit
import RoutingHTTPServer

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var bgTask = UIBackgroundTaskInvalid
    let server = HTTPServer()

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        application.openURL(NSURL(string: "http://localhost:55555")!)
        return true
    }

    func applicationDidEnterBackground(application: UIApplication) {
        bgTask = application.beginBackgroundTaskWithExpirationHandler() {
            dispatch_async(dispatch_get_main_queue()) {[unowned self] in
                application.endBackgroundTask(self.bgTask)
                self.bgTask = UIBackgroundTaskInvalid
            }
        }
    }
}

class HTTPServer: RoutingHTTPServer {
    override init() {
        super.init()
        setPort(55555)
        handleMethod("GET", withPath: "/") {
            $1.setHeader("Content-Type", value: "application/x-apple-aspen-config")
            $1.respondWithData(NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("udid", ofType: "mobileconfig")!)!)
        }
        handleMethod("POST", withPath: "/") {
            let raw = NSString(data:$0.body(), encoding:NSISOLatin1StringEncoding) as! String
            let plistString = raw.substringWithRange(Range(start: raw.rangeOfString("<?xml")!.startIndex,end: raw.rangeOfString("</plist>")!.endIndex))
            let plist = NSPropertyListSerialization.propertyListWithData(plistString.dataUsingEncoding(NSISOLatin1StringEncoding)!, options: .allZeros, format: nil, error: nil) as! [String:String]

            let udid = plist["UDID"]! 
            println(udid) // Here is your UDID!

            $1.statusCode = 200
            $1.respondWithString("see https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/ConfigurationProfileExamples/ConfigurationProfileExamples.html")
        }
        start(nil)
    }
}

Вот содержание udid.mobileconfig:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>PayloadContent</key>
        <dict>
            <key>URL</key>
            <string>http://localhost:55555</string>
            <key>DeviceAttributes</key>
            <array>
                <string>IMEI</string>
                <string>UDID</string>
                <string>PRODUCT</string>
                <string>VERSION</string>
                <string>SERIAL</string>
            </array>
        </dict>
        <key>PayloadOrganization</key>
        <string>udid</string>
        <key>PayloadDisplayName</key>
        <string>Get Your UDID</string>
        <key>PayloadVersion</key>
        <integer>1</integer>
        <key>PayloadUUID</key>
        <string>9CF421B3-9853-9999-BC8A-982CBD3C907C</string>
        <key>PayloadIdentifier</key>
        <string>udid</string>
        <key>PayloadDescription</key>
        <string>Install this temporary profile to find and display your current device's UDID. It is automatically removed from device right after you get your UDID.</string>
        <key>PayloadType</key>
        <string>Profile Service</string>
    </dict>
</plist>

Установка профиля не удастся (я не удосужился реализовать ожидаемый ответ, см. Документацию ), но приложение получит правильный UDID. И вы также должны подписать mobileconfig .

Bzz
источник
1

Для Swift 3.0, пожалуйста, используйте код ниже.

let deviceIdentifier: String = (UIDevice.current.identifierForVendor?.uuidString)!
NSLog("output is : %@", deviceIdentifier)
Ganesh
источник
1
iOS 11 представила инфраструктуру DeviceCheck. Он имеет полностью защищенное решение для уникальной идентификации устройства.
Сантош Ботре
1

Ты можешь использовать

NSString *sID = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];

Который уникален для устройства во всех приложениях.

Dhaval
источник
1

Apple добавила новый фреймворк в iOS 11 под названием DeviceCheck, который поможет вам очень легко получить уникальный идентификатор. Прочитайте эту форму больше информации. https://medium.com/@santoshbotre01/unique-identifier-for-the-ios-devices-590bb778290d

Сантош Ботре
источник
Но для этого нужно подключение к интернету, не так ли?
Ник Ков
Да, для этого нужно подключение к интернету.
Сантош Ботре
0

Если кто-то наткнулся на этот вопрос, то при поиске альтернативы. Я следовал этому подходу в IDManagerклассе, это коллекция из разных решений. KeyChainUtil - это оболочка для чтения из цепочки для ключей. Вы также можете использовать hashed MAC addressкак своего рода уникальный идентификатор.

/*  Apple confirmed this bug in their system in response to a Technical Support Incident 
    request. They said that identifierForVendor and advertisingIdentifier sometimes 
    returning all zeros can be seen both in development builds and apps downloaded over the 
    air from the App Store. They have no work around and can't say when the problem will be fixed. */
#define kBuggyASIID             @"00000000-0000-0000-0000-000000000000"

+ (NSString *) getUniqueID {
    if (NSClassFromString(@"ASIdentifierManager")) {
        NSString * asiID = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
        if ([asiID compare:kBuggyASIID] == NSOrderedSame) {
            NSLog(@"Error: This device return buggy advertisingIdentifier.");
            return [IDManager getUniqueUUID];
        } else {
            return asiID;
        }

    } else {
        return [IDManager getUniqueUUID];
    }
}


+ (NSString *) getUniqueUUID {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:kBuyassUser andServiceName:kIdOgBetilngService error:&error];
    if (error) {
        NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
        return nil;
    }
    if (!uuid) {
        DLog(@"No UUID found. Creating a new one.");
        uuid = [IDManager GetUUID];
        uuid = [Util md5String:uuid];
        [KeychainUtils storeUsername:USER_NAME andPassword:uuid forServiceName:SERVICE_NAME updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error getting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}

/* NSUUID is after iOS 6. */
+ (NSString *)GetUUID
{
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return [(NSString *)string autorelease];
}

#pragma mark - MAC address
// Return the local MAC addy
// Courtesy of FreeBSD hackers email list
// Last fallback for unique identifier
+ (NSString *) getMACAddress
{
    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;

    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;

    if ((mib[5] = if_nametoindex("en0")) == 0) {
        printf("Error: if_nametoindex error\n");
        return NULL;
    }

    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }

    if ((buf = malloc(len)) == NULL) {
        printf("Error: Memory allocation error\n");
        return NULL;
    }

    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2\n");
        free(buf); // Thanks, Remy "Psy" Demerest
        return NULL;
    }

    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];

    free(buf);
    return outstring;
}

+ (NSString *) getHashedMACAddress
{
    NSString * mac = [IDManager getMACAddress];
    return [Util md5String:mac];
}

+ (NSString *)md5String:(NSString *)plainText
{
    if(plainText == nil || [plainText length] == 0)
        return nil;

    const char *value = [plainText UTF8String];
    unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5(value, strlen(value), outputBuffer);

    NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
        [outputString appendFormat:@"%02x",outputBuffer[count]];
    }
    NSString * retString = [NSString stringWithString:outputString];
    [outputString release];
    return retString;
}
Karim
источник
0
+ (NSString *) getUniqueUUID {
    NSError * error;
    NSString * uuid = [KeychainUtils getPasswordForUsername:kBuyassUser andServiceName:kIdOgBetilngService error:&error];
    if (error) {
    NSLog(@"Error geting unique UUID for this device! %@", [error localizedDescription]);
    return nil;
    }
    if (!uuid) {
        DLog(@"No UUID found. Creating a new one.");
        uuid = [IDManager GetUUID];
        uuid = [Util md5String:uuid];
        [KeychainUtils storeUsername:USER_NAME andPassword:uuid forServiceName:SERVICE_NAME updateExisting:YES error:&error];
        if (error) {
            NSLog(@"Error getting unique UUID for this device! %@", [error localizedDescription]);
            return nil;
        }
    }
    return uuid;
}
Махеш чаудары
источник
0

Мы можем использовать идентификатор ForVendor для ios7,

-(NSString*)uniqueIDForDevice
{
    NSString* uniqueIdentifier = nil;
    if( [UIDevice instancesRespondToSelector:@selector(identifierForVendor)] ) { // >=iOS 7
        uniqueIdentifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    } else { //<=iOS6, Use UDID of Device       
            CFUUIDRef uuid = CFUUIDCreate(NULL);
            //uniqueIdentifier = ( NSString*)CFUUIDCreateString(NULL, uuid);- for non- ARC
            uniqueIdentifier = ( NSString*)CFBridgingRelease(CFUUIDCreateString(NULL, uuid));// for ARC
            CFRelease(uuid);
         }
    }
return uniqueIdentifier;
}

--Важная заметка ---

UDID и идентификатор ForVendor различаются: ---

1.) On uninstalling  and reinstalling the app identifierForVendor will change.

2.) The value of identifierForVendor remains the same for all the apps installed from the same vendor on the device.

3.) The value of identifierForVendor also changes for all the apps if any of the app (from same vendor) is reinstalled.
HDdeveloper
источник
ты уверен ? мы можем использовать идентификатор forVendor для ios7?
Авис
0

Apple скрыла UDID от всех общедоступных API, начиная с iOS 7. Любой UDID, начинающийся с FFFF, является поддельным идентификатором. Приложения «Отправить UDID», которые ранее работали, больше нельзя использовать для сбора UDID для тестовых устройств. (вздох!)

UDID отображается, когда устройство подключено к XCode (в органайзере) и когда устройство подключено к iTunes (хотя вы должны нажать «Серийный номер», чтобы отобразить идентификатор.

Если вам нужно получить UDID для устройства, чтобы добавить его в профиль обеспечения, и вы не можете сделать это самостоятельно в XCode, вам придется пройти их шаги, чтобы скопировать / вставить его из iTunes.

Есть ли способ с тех пор (выпуск iOS 7) получить UDID без использования iTunes на ПК / Mac?

Прит
источник
0

У меня тоже возникла проблема, и решение простое:

    // Get Bundle Info for Remote Registration (handy if you have more than one app)
    NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"];
    NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];


    // Get the users Device Model, Display Name, Unique ID, Token & Version Number
    UIDevice *dev = [UIDevice currentDevice];
    NSString *deviceUuid=[dev.identifierForVendor  UUIDString];

    NSString *deviceName = dev.name;
Ахмет Казим Гюней
источник
0

Не идеальная, но одна из лучших и ближайших альтернатив UDID (в Swift с использованием iOS 8.1 и Xcode 6.1):

Генерация случайного UUID

let strUUID: String = NSUUID().UUIDString

И используйте библиотеку KeychainWrapper :

Добавьте строковое значение в цепочку для ключей:

let saveSuccessful: Bool = KeychainWrapper.setString("Some String", forKey: "myKey")

Получить строковое значение из цепочки для ключей:

let retrievedString: String? = KeychainWrapper.stringForKey("myKey")

Удалить строковое значение из цепочки для ключей:

let removeSuccessful: Bool = KeychainWrapper.removeObjectForKey("myKey")

В этом решении используется цепочка для ключей, поэтому запись, хранящаяся в цепочке для ключей, будет сохраняться даже после удаления и повторной установки приложения. Единственный способ удалить эту запись - сбросить все содержимое и настройки устройства. Вот почему я упомянул, что это решение замещения не является идеальным, но остается одним из лучших решений для замены UDID на iOS 8.1 с использованием Swift.

Король-Мастер
источник
0

NSLog (@ "% @", [[UIDevice currentDevice] identifierForVendor]);

Анкит Гарг
источник