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

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

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

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

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

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

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

32 ответа

Решение

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 для каждой установки.

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

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

Основываясь на ссылке, предложенной @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 - (режим самолета) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (режим AirPlane) GlobalAppUDID

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

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

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

Проверь это,

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

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

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

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

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

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

Пример:

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

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

Вы можете сохранить его в KEYCHAIN на самом первом запуске вашего приложения. Так что после первого запуска мы можем просто использовать его из цепочки для ключей, не нужно его регенерировать. Основная причина использования 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"];

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

[UIDevice currentDevice].identifierForVendor.UUIDString

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

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

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

В основном, чтобы соответствовать UDIDнеобходимы следующие функции:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Я бы также предложил перейти от uniqueIdentifier в эту библиотеку с открытым исходным кодом (на самом деле 2 простые категории), которая использует MAC-адрес устройства вместе с идентификатором комплекта приложений для создания уникального идентификатора в ваших приложениях, который можно использовать в качестве замены 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

Вы можете добиться из этого кода: UIDevice-with-UniqueIdentifier-for-iOS-5

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

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

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

Используя 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;

}

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

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

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

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

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

Для iOS 5 обратитесь по этой ссылке https://github.com/gekitz/UIDevice-with-UniqueIdentifier-for-iOS-5

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

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

Это код, который я использую, чтобы получить идентификатор для 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];
}

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

Начиная с iOS 6, мы имеем NSUUID класс, который соответствует RFC4122

Apple Link: apple_ref для NSUUID

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

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

Рабочий способ получить 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.

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

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

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

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

Если кто-то наткнулся на этот вопрос, то при поиске альтернативы. Я следовал этому подходу в 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;
}

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

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

Не идеальная, но одна из лучших и ближайших альтернатив 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.

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

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

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

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

Мы можем использовать идентификатор 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.
+ (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;
}
Другие вопросы по тегам