Застарений унікальний ідентифікатор UIDevice - що робити зараз?


501

Він тільки що прийшов до світла , що властивості UIDevice UniqueIdentifier засуджуються в прошивці 5 і недоступно в прошивці 7 і вище. Немає альтернативних методів чи властивостей, як видається, недоступними чи наступними.

Багато наших існуючих додатків тісно залежать від цієї властивості для унікального визначення конкретного пристрою. Як ми можемо вирішити цю проблему вперед?

Пропозиція з документації в 2011-2012 роках :

Спеціальні міркування

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

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


1
Для додатків, які все ще використовують унікальний ідентифікатор, iOS7 тепер повертає FFFFFFFF + ідентифікаторForVendor, який порушує багато неправильно написаних не поновлюваних програм підписки.
Ритмічний фістман

Якщо пощастило, що ваш додаток використовує Push Notifications, ви можете використовувати маркер, надісланий назад із служби push Apple, це унікально для кожного пристрою
Calin Chitu

@CalinChitu Якщо користувач не приймає push-сповіщення, ви все ще отримуєте pushID для цього користувача?
Чейз Робертс

Відповіді:


272

UUID, створений користувачем CFUUIDCreate , унікальний, якщо користувач видаляє та повторно встановлює додаток: ви отримуватимете новий щоразу.

Але, можливо, ви хочете, щоб він не був унікальним, тобто він повинен залишатися таким же, коли користувач видаляє та перевстановить додаток. Це вимагає трохи зусиль, оскільки найбільш надійним ідентифікатором пристрою є MAC-адреса. Ви можете запитувати MAC і використовувати його як UUID.

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

Редагування 2: Як вказували інші, кращим рішенням, оскільки iOS 6 є - [ідентифікатор UIDeviceForVendor] . У більшості випадків ви повинні мати можливість використовувати його як заміну для старого -[UIDevice uniqueIdentifier](але UUID, який створюється при першому запуску програми, - це те, що, схоже, Apple хоче, щоб ви використовували).

Редагування 3: Отже, цей головний момент не губиться в шумі коментарів: не використовуйте MAC як UUID, створіть хеш за допомогою MAC . Цей хеш завжди буде створювати однаковий результат кожного разу, навіть через перевстановлення та додатки (якщо хешування буде виконано однаково). У будь-якому разі, в даний час (2013 р.) Це вже не потрібно, за винятком випадків, коли вам потрібен "стабільний" ідентифікатор пристрою на iOS <6.0.

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


8
Чи не змінюється mac-адреса залежно від того, підключений користувач через Wifi чи ні?
Олівер Пірмен

1
@DarkDust: але оскільки активний інтерфейс змінюється при переході з wifi на стільниковий модем, MAC-адреса активного інтерфейсу також повинна змінюватися; якщо ви завжди вибираєте певний інтерфейс, щоб отримати MAC
user102008

3
@Roger Nolan: Будь ласка, не редагуйте відповіді інших людей та додайте матеріали, схожі на оригінал автора. Дякую.
DarkDust

2
@RogerNolan Поки публікація не є відповіддю спільноти, правки призначені для виправлення помилок і подібних речей, а не для додавання нових матеріалів. Є причина, що ви заробили пільгу. Уявіть, що я редагую вашу відповідь і пишу деякі БС, люди думають, що ви це написали. Я сумніваюся, що вам це сподобається :-) Але ви не отримуєте повідомлення те, що зміни відбулися, я дізнався лише випадково.
DarkDust

3
Зараз Apple відхиляє програми, які використовують хешований MAC.
Ідан

91

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

Ви можете знайти код на github


3
Ця реалізація є унікальною (MAC-адреса) для пристрою через перевстановлення, як, наприклад, UniIIl Apple, але також поважає конфіденційність, будучи також унікальною для програми (також використовувати bundleId) ... Потрібно мати імхо, що 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/…
Хеджазі

61

На основі посилання, запропонованого @moonlight, я зробив кілька тестів і, здається, це найкраще рішення. Як говорить @DarkDust, метод перевіряє, en0що завжди доступно.
Є два варіанти:
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) після видалення та встановлення програми

Сподіваюся, що це корисно.

EDIT:
Як зазначали інші, це рішення в iOS 7 вже не корисне, оскільки uniqueIdentifierбільше не доступне, і запит на MAC-адресу тепер повертається завжди 02: 00: 00: 00: 00: 00


13
ця робота не працює на iOS7, Apple виключає використання MAC-адреси.
Сарим Сідд

@SarimSidd На даний момент інформація про iOS 7 знаходиться під NDA, ми не можемо обговорювати тут.
Мат

57

заціни,

ми можемо використовувати Keychain замість NSUserDefaultsкласу, щоб зберігати UUIDстворені CFUUIDCreate.

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

UUID буде відтворено саме під час скидання пристрою користувачем.

Я спробував цей метод з SFHFKeychainUtils, і він працює як шарм.


33
Цей метод є надійною заміною UDID. Він також має додаткову перевагу відтворення ідентифікатора у форматі пристрою (наприклад, якщо пристрій змінює власника). Однак важливо зазначити, що брелок можна відновити на інших пристроях, якщо користувач шифрує їх резервну копію. Це може призвести до ситуації, коли кілька пристроїв поділяють один і той же UUID. Щоб цього уникнути, встановіть доступність елемента вашого брелка на kSecAttrAccessibleAlwaysThisDeviceOnly. Це забезпечить, щоб ваш UUID не мігрував на будь-який інший пристрій. Щоб отримати доступ до свого UUID з інших програм, використовуйте kSecAttrAccessGroupключ.
Jeevan Takhar

Де саме (який ключ) ви повинні використовувати для зберігання UUID в брелоку?
втраченопереклад

Опс! посилання розірвано
COVID19

48

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

Насправді він стає унікальним ідентифікатором користувача , наскільки ви стурбовані. (навіть краще, ніж ідентифікатор пристрою ).

Приклад:

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

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

Потім ви можете зберігати його під KEYCHAINчас першого запуску програми. Так що після першого запуску ми можемо просто використовувати його з брелка, не потрібно регенерувати його. Основна причина використання Keychain для зберігання: Коли ви встановите UUIDKeychain, він зберігатиметься, навіть якщо користувач повністю видалить додаток, а потім встановить його знову. . Отже, це постійний спосіб його зберігання, а значить, ключ буде унікальним на всьому шляху.

     #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 після циклу видалення / перевстановлення + підтвердженого подання яблучного додатка?
mindbomb

Я почав використовувати це рішення. Кілька тестів на 2 пристроях (відновити, перевстановити, вимкнути пристрій) показали мені, що id - це той самий. iOS 10.3.
деко

16

Можливо, ви можете використовувати:

[UIDevice currentDevice].identifierForVendor.UUIDString

Документація Apple описує ідентифікаторForVender наступним чином:

Значення цього властивості однакове для програм, які надходять від того самого постачальника, що працює на тому ж пристрої. Різне значення повертається для програм на одному пристрої, що надходять від різних постачальників, і для додатків на різних пристроях незалежно від постачальника.


Цікаво, чому до недавнього часу ніхто не підніс це… І тепер я бачу, що це нове з 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!


Мені дуже цікаво, як це працює? Код написаний в Objective-C, але не існує іншого хорошого рішення, яке б відповідало вимогам, зазначеним вище, так що ж робить цю рамку різною? Рішення, яке використовує цей фреймворк, також має бути можливим розмістити як запропоновану відповідь тут ...
jake_hetfield

Я погоджуюся - MAC-адресу можна також налаштувати вручну ("клоновано"), хоча це, мабуть, здебільшого. Я повинен протестувати проти D в UDID. Це не ідентифікатор пристрою, це UUID (універсальний унікальний ідентифікатор). Apple (Ідентифікатор пристрою) на кожному пристрої в ПЗУ розміщена печаткою компанії 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 на інших пристроях, навіть якщо резервна копія зашифрована.
Jeevan Takhar

Це справді поведінка, яку я бачив багато разів. Наприклад, я реєструю свій iPhone для Google Sync. Тоді я отримав новий iPhone, зареєстрував його та вуаля - тепер у моїх налаштуваннях синхронізації перераховано 2 iPhone.
Джей Імерман

11

Схоже на iOS 6, Apple рекомендує використовувати клас NSUUID .

З повідомлення тепер у документах UIDevice для uniqueIdentifierвластивості:

Застаріло в iOS 5.0. Використовуйте властивість identifierForVendor цього класу або властивість рекламного ідентифікатора класу ASIdentifierManager замість, як це доречно, або використовуйте метод UUID класу NSUUID для створення UUID та запишіть його в базу даних користувачів за замовчуванням.


10

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

UIDevice *myDevice=[UIDevice currentDevice];
NSString *UUID = [[myDevice identifierForVendor] UUIDString];

1
Я використав цей код. Але коли я видалив додаток і знову встановив, я отримав новий Id
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 щодо цієї теми та / або подати запит на помилку / функцію щодо цього, оскільки, можливо, вони навіть не знають про всі наслідки для розробників.


13
Важлива точка, однак я вважаю, що UUID також може бути підроблений / заблокований на телефоні з розбиттям, так що технічно існуючий [унікальний ідентифікатор UIDevice] є таким же недоліком.
Олівер Пірмен

3
Ви завжди можете створити ідентифікатор на сервері та зберегти його на пристрої. Ось як це робить більшість додатків. Я не розумію, чому програмістам iOS потрібно щось особливе.
Султан

1
@Sulthan не працює на iOS, тому що якщо ви видалите додаток, всі його дані будуть втрачені, тому немає можливості гарантувати таким чином унікальний ідентифікатор пристрою.
lkraider

4
Не, якщо ви збережете його в брелок. У всякому разі, я ніколи не бачив програми, де це була проблема. Якщо додаток і дані видалено, вам не потрібен той самий ідентифікатор пристрою. Якщо ви хочете ідентифікувати користувача, попросіть його на електронну пошту.
Султан

Доступ до 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;

}


3

Наступний код допомагає отримати UDID:

        udid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
        NSLog(@"UDID : %@", udid);

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?
Василь Бурк

Більше не можна використовувати для цього рекламний ідентифікатор, оскільки 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. А також слід підписати мобільну конфігу .


1

Для Swift 3.0 використовуйте код нижче.

let deviceIdentifier: String = (UIDevice.current.identifierForVendor?.uuidString)!
NSLog("output is : %@", deviceIdentifier)

1
iOS 11 представив рамку DeviceCheck. Він має повноцінне рішення для унікальної ідентифікації пристрою.
Сантош Ботре

1

Можна використовувати

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

Що є унікальним для пристрою у всіх програмах.


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

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.

ти впевнений ? чи можемо ми використовувати ідентифікаторForVendor для ios7 ,?
Avis

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.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.