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

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

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

документация в 2011-2012 годах была предложена:

Special Considerations

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

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

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

EDIT:
Как отмечали другие, это решение в iOS 7 уже не полезно, поскольку uniqueIdentifier больше не доступно, и запрос MAC-адреса теперь возвращается всегда 02: 00: 00: 00: 00: 00

Ответ 4

проверьте это,

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

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

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

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

Ответ 5

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

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

Пример:

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

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

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

     #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 в свой проект и добавьте "Безопасность .framework" в ваш проект. Чтобы использовать UUID, просто используйте:

NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];

Ответ 6

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

[UIDevice currentDevice].identifierForVendor.UUIDString

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

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

Ответ 7

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

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

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

OpenUDID выполняет вышеизложенное и даже имеет встроенный механизм Opt-Out для последующего рассмотрения.

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

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

Ответ 8

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

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

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

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

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

Ответ 9

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

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

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

Ответ 10

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

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

Ответ 11

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

Ответ 13

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

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

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

Ответ 14

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

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

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

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

Доступно в iOS 6.0 и более поздних версиях и объявлено в UIDevice.h

Для iOS 5 ссылайтесь на эту ссылку UIDevice-with-UniqueIdentifier-for-iOS-5

Ответ 15

Использование 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;

}

Ответ 16

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

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

Ответ 17

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

Ответ 18

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

Apple Link: apple_ref для NSUUID

Ответ 19

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

Ответ 20

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

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

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

Ответ 21

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

  • Запустите веб-сервер внутри приложения с двумя страницами: нужно вернуть специально созданный профиль MobileConfiguration, а другой должен собирать UDID. Подробнее здесь, здесь и здесь.
  • Вы открываете первую страницу в 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 UDID. It is automatically removed from device right after you get your UDID.</string>
        <key>PayloadType</key>
        <string>Profile Service</string>
    </dict>
</plist>

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

Ответ 23

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

Ответ 25

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

Ответ 26

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

Ответ 27

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

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

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

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

Ответ 28

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

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

Ответ 29

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

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

Ответ 30

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

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