UIDevice uniqueIdentifier obsoleto: cosa fare adesso?


501

È appena emerso che la proprietà uniqueIdentifier di UIDevice è obsoleta in iOS 5 e non disponibile in iOS 7 e versioni successive. Nessun metodo o proprietà alternativa sembra essere disponibile o disponibile.

Molte delle nostre app esistenti dipendono strettamente da questa proprietà per identificare in modo univoco un determinato dispositivo. Come potremmo gestire questo problema in futuro?

Il suggerimento dalla documentazione nel 2011-2012 era:

considerazioni speciali

Non utilizzare la proprietà uniqueIdentifier. Per creare un identificatore univoco specifico per la tua app, puoi chiamare la CFUUIDCreatefunzione per crearne una UUIDe scriverla nel database delle impostazioni predefinite usando la NSUserDefaultsclasse.

Tuttavia, questo valore non sarà lo stesso se un utente disinstalla e reinstalla l'app.


1
Per le app che utilizzano ancora uniqueIdentifier, iOS7 ora restituisce FFFFFFFF + identifierForVendor, che interrompe molte app di abbonamento non rinnovate scritte male.
Rhythmic Fistman,

Se per fortuna la tua app utilizza le notifiche push, puoi utilizzare il token inviato dal servizio push di apple, è unico anche per dispositivo
Calin Chitu

@CalinChitu Se l'utente non accetta le notifiche push, ricevi comunque un ID push per quell'utente?
Chase Roberts,

Risposte:


272

Un UUID creato da CFUUIDCreate è unico se un utente disinstalla e reinstalla l'app: ne otterrai una nuova ogni volta.

Ma potresti desiderare che non sia univoco, ovvero dovrebbe rimanere lo stesso quando l'utente disinstalla e reinstalla l'app. Ciò richiede un po 'di sforzo, poiché l'identificatore per dispositivo più affidabile sembra essere l'indirizzo MAC. È possibile eseguire una query sul MAC e utilizzarlo come UUID.

Modifica: ovviamente è necessario interrogare sempre il MAC della stessa interfaccia. Immagino che la scommessa migliore sia con en0. Il MAC è sempre presente, anche se l'interfaccia non ha IP / è inattivo.

Modifica 2: Come è stato sottolineato da altri, la soluzione preferita da iOS 6 è - [UIDevice identifierForVendor] . Nella maggior parte dei casi, dovresti essere in grado di usarlo come sostituto del vecchio -[UIDevice uniqueIdentifier](ma un UUID che viene creato quando l'app viene avviata per la prima volta è ciò che Apple sembra voler utilizzare).

Modifica 3: Quindi questo punto importante non si perde nel rumore dei commenti: non usare il MAC come UUID, crea un hash usando il MAC . Questo hash creerà sempre lo stesso risultato ogni volta, anche attraverso le reinstallazioni e le app (se l'hashing viene eseguito allo stesso modo). Ad ogni modo, al giorno d'oggi (2013) questo non è più necessario tranne se è necessario un identificatore del dispositivo "stabile" su iOS <6.0.

Modifica 4: In iOS 7, Apple ora restituisce sempre un valore fisso quando interroga il MAC per contrastare specificamente il MAC come base per uno schema ID . Quindi ora dovresti davvero usare - [UIDevice identifierForVendor] o creare un UUID per installazione.


8
L'indirizzo mac non cambia a seconda che l'utente sia connesso tramite Wifi o no?
Oliver Pearmain,

1
@DarkDust: ma poiché l'interfaccia attiva cambia quando si passa dal modem wifi al modem cellulare, anche l'indirizzo MAC dell'interfaccia attiva dovrebbe cambiare; a meno che tu non scelga sempre un'interfaccia particolare per ottenere il MAC
user102008

3
@Roger Nolan: Per favore, non modificare le risposte degli altri e aggiungere elementi che sembrano provenire dall'autore originale. Grazie.
DarkDust,

2
@RogerNolan Finché post non è una risposta della comunità, le modifiche servono per correggere errori e cose del genere, non per aggiungere nuove cose. C'è un motivo per cui hai guadagnato il privilegio. Immagina di modificare la tua risposta e scrivere qualche BS, la gente penserebbe che tu l'avresti scritto. Dubito che ti piacerebbe :-) Ma non vieni avvisato che è avvenuta una modifica, l'ho scoperto solo per caso.
DarkDust

3
Apple ora rifiuta le app che utilizzano l'hash MAC.
Idan,

91

Puoi già utilizzare la tua alternativa per Apple UDID. Il tipo gentile gekitz ha scritto una categoria in UIDevicecui genererà un qualche tipo di UDIDindirizzo mac del dispositivo e identificatore del pacchetto.

Puoi trovare il codice su github


3
Questa implementazione è univoca (indirizzo MAC) per un dispositivo attraverso reinstallazioni, come uniqueId di Apple, ma rispetta anche la privacy, essendo anche unica per un'applicazione (usa anche bundleId) ... Un must have imho, che Apple dovrebbe includere nelle sue API. .. invece di deprecare senza alternative.
Vincent Guerci,

8
Anche se usa la vecchia licenza bsd con la clausola pubblicitaria, schifo.
jbtule,

8
Per chiunque altro stia trovando questo post, la licenza è stata cambiata dal commento sopra di jbtule.
James

1
Come discusso in questo commento di commit, la libreria così com'è pone un grave problema di perdita di privacy e non dovrebbe essere usata:
Sarà il

15
A partire da iOS 7, il sistema restituisce sempre il valore 02:00:00:00:00:00quando si richiede l'indirizzo MAC su qualsiasi dispositivo. Controlla qui: developer.apple.com/library/prerelease/ios/releasenotes/General/…
Hejazi l'

61

Sulla base del link proposto da @moonlight, ho fatto diversi test e sembra essere la soluzione migliore. Come dice @DarkDust il metodo va a verificare en0quale è sempre disponibile.
Sono disponibili 2 opzioni:
uniqueDeviceIdentifier(MD5 di MAC + CFBundleIdentifier)
e uniqueGlobalDeviceIdentifier(MD5 di MAC), restituiscono sempre gli stessi valori.
Di seguito i test che ho fatto (con il dispositivo reale):

#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 - (Modalità AirPlane) UDID
XXXX7dc3c577446a2bcbd77935bdXXXX - (Modalità AirPlane) GlobalAppUDID

XXXX21f1f19edff198e2a2356bf4XXXX - (Wi-Fi) dopo aver rimosso e reinstallato l'app XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) dopo aver rimosso e installato l'app

Spero sia utile.

MODIFICARE:
Come altri hanno sottolineato, questa soluzione in iOS 7 non è più utile poiché uniqueIdentifiernon è più disponibile e la query per l'indirizzo MAC ora restituisce sempre 02: 00: 00: 00: 00: 00


13
questo non funzionerà su iOS7, Apple elimina l'uso dell'indirizzo MAC.
Sarim Sidd,

@SarimSidd Per ora le informazioni su iOS 7 sono sotto NDA, non possiamo discutere qui.
Mat

57

controllalo,

possiamo usare Keychain anziché NSUserDefaultsclasse, per archiviare UUIDcreato da CFUUIDCreate.

in questo modo potremmo evitare la UUIDricreazione con la reinstallazione e ottenere sempre lo stesso UUIDper la stessa applicazione anche l'utente disinstallare e reinstallare di nuovo.

UUID verrà ricreato proprio quando il dispositivo verrà ripristinato dall'utente.

Ho provato questo metodo con SFHFKeychainUtils ed è un incantesimo.


33
Questo metodo è un solido sostituto di UDID. Ha anche l'ulteriore vantaggio di ricreare l'identificatore sul formato del dispositivo (ad es. Se il dispositivo cambia proprietario). Tuttavia, è importante notare che il portachiavi può essere ripristinato su altri dispositivi se l'utente crittografa il proprio backup. Ciò può provocare una situazione in cui più dispositivi condividono lo stesso UUID. Per evitare ciò, imposta l'accessibilità dell'elemento portachiavi su kSecAttrAccessibleAlwaysThisDeviceOnly. Questo assicurerà che il tuo UUID non migra su nessun altro dispositivo. Per accedere al tuo UUID da altre app, utilizza la kSecAttrAccessGroupchiave.
Jeevan Takhar,

Dove esattamente (quale chiave) dovresti usare per memorizzare l'UUID nel portachiavi?
lostintranslation

Opps! il collegamento è interrotto
COVID19

48

Crea il tuo UUID e poi memorizzalo nel Portachiavi. Pertanto, persiste anche quando l'app viene disinstallata. In molti casi persiste anche se l'utente esegue la migrazione tra dispositivi (ad es. Backup completo e ripristino su un altro dispositivo).

In effetti diventa un identificatore utente unico per quanto ti riguarda. (anche meglio dell'identificatore del dispositivo ).

Esempio:

Sto definendo un metodo personalizzato per creare un UUIDas:

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

Puoi quindi archiviarlo KEYCHAINal primo avvio della tua app. In modo che dopo il primo lancio, possiamo semplicemente usarlo dal portachiavi, non è necessario rigenerarlo. Il motivo principale per cui si utilizza Keychain per l'archiviazione è: quando si imposta il UUIDPortachiavi, persisterà anche se l'utente disinstalla completamente l'app e quindi la reinstalla. . Quindi, questo è il modo permanente di memorizzarlo, il che significa che la chiave sarà unica fino in fondo.

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

All'avvio dell'applicazione includere il seguente codice:

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

Scarica i file SSKeychain.m e .h da sskeychain e trascina i file SSKeychain.m e .h nel tuo progetto e aggiungi "Security.framework" al tuo progetto. Per usare l'UUID in seguito basta semplicemente usare:

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

Perché un identificatoreForVendor funziona non è perfettamente. In alcuni casi può restituire un valore zero o 0x0. Questo metodo sembra funzionare perfettamente
CReaTuS

3
qualcuno ha convalidato che funziona su iOS7 dopo il ciclo di disinstallazione / reinstallazione + invio verificato dell'app apple?
mindbomb,

Ho iniziato a usare questa soluzione. Diversi test su 2 dispositivi (ricostruzione, reinstallazione, spegnimento del dispositivo) mi hanno mostrato che l'id è lo stesso. iOS 10.3.
deko,

16

Forse puoi usare:

[UIDevice currentDevice].identifierForVendor.UUIDString

La documentazione di Apple descrive l'identificatore ForVender come segue:

Il valore di questa proprietà è lo stesso per le app che provengono dallo stesso fornitore in esecuzione sullo stesso dispositivo. Viene restituito un valore diverso per le app sullo stesso dispositivo che provengono da fornitori diversi e per le app su dispositivi diversi indipendentemente dal fornitore.


Curioso perché nessuno lo abbia
menzionato

1
Se l'utente aggiorna iOS e / o installa un nuovo iOS, il valore dell'identificatore ForVendor cambierà o rimarrà lo stesso?
Sunil Zalavadiya,

1
Dopo aver rimosso tutte le app dallo stesso fornitore, questo valore verrà modificato.
Mitesh Khatri,

14

Puoi prendere in considerazione l'utilizzo di OpenUDIDquale rimpiazzo di sostituzione è obsoleto UDID.

Fondamentalmente, per abbinare UDID, sono richieste le seguenti funzionalità:

  1. unico o sufficientemente unico (una collisione a bassa probabilità è probabilmente molto accettabile)
  2. persistenza tra riavvii, ripristini, disinstallazioni
  3. disponibile su app di diversi fornitori (utile per acquisire utenti tramite reti CPI) -

OpenUDID soddisfa quanto sopra e ha persino un meccanismo di opt-out incorporato per successive considerazioni.

Controlla http://OpenUDID.org che punta al GitHub corrispondente. Spero che sia di aiuto!

Come nota a margine, vorrei evitare qualsiasi alternativa di indirizzo MAC. Mentre l'indirizzo MAC appare come una soluzione allettante e universale, assicurati che questo frutto appeso basso sia avvelenato. L'indirizzo MAC è molto sensibile e Apple potrebbe benissimo deprecare l'accesso a questo prima ancora di poter dire "INVIA QUESTA APP" ... l'indirizzo di rete MAC viene utilizzato per autenticare determinati dispositivi su prestiti privati ​​(WLAN) o altri private virtuali reti (VPN). .. è persino più sensibile del precedente UDID!


Sono davvero curioso di come funziona? Il codice è scritto in Objective-C, ma non esiste un'altra buona soluzione che soddisfi i requisiti di cui sopra, quindi cosa rende questo framework diverso? La soluzione utilizzata da questo framework dovrebbe anche essere possibile pubblicare qui come risposta suggerita ...
jake_hetfield

Concordo: anche l'indirizzo MAC può essere configurato manualmente ("clonato"), sebbene non sia probabile per la maggior parte. Devo protestare contro la D in UDID. Questo non è un ID dispositivo, è un UUID (identificatore univoco universale). L'ID dispositivo è timbrato da Apple dalla fabbrica su ciascun dispositivo nella ROM.
Jay Imerman,

La migliore soluzione anche per iOS7 è ciò che è effettivamente necessario per identificare un dispositivo in modo univoco
Vishal Dharankar,

1
OpenUDID è obsoleto e non è raccomandato l'uso
mkll

11

Sono sicuro che Apple ha infastidito molte persone con questo cambiamento. I sviluppare un app contabilità per iOS e hanno un servizio online per la sincronizzazione modifiche apportate su dispositivi diversi. Il servizio mantiene un database di tutti i dispositivi e le modifiche che devono essere propagate ad essi. Pertanto è importante sapere quali dispositivi sono quali. Sto monitorando i dispositivi utilizzando UIDevice uniqueIdentifier e per quello che vale, ecco i miei pensieri.

  • Generare un UUID e archiviare le impostazioni predefinite dell'utente? Non va bene perché questo non persiste quando l'utente elimina l'app. Se si installano di nuovo in un secondo momento, il servizio online non dovrebbe creare un nuovo record di dispositivo, ciò sprecherebbe risorse sul server e fornirà un elenco di dispositivi contenenti lo stesso due o più volte. Gli utenti vedrebbero elencati più di un "iPhone di Bob" se hanno reinstallato l'app.

  • Generare un UUID e archiviarlo nel portachiavi? Questo era il mio piano, poiché persiste anche quando l'app viene disinstallata. Ma quando si ripristina un backup di iTunes su un nuovo dispositivo iOS, il portachiavi viene trasferito se il backup è crittografato. Ciò potrebbe portare a due dispositivi contenenti lo stesso ID dispositivo se il vecchio e il nuovo dispositivo sono entrambi in servizio. Questi dovrebbero essere elencati come due dispositivi nel servizio online, anche se il nome del dispositivo è lo stesso.

  • Generare un hash indirizzo MAC e ID bundle? Questa sembra la migliore soluzione per ciò di cui ho bisogno. Eseguendo l'hashing con l'id bundle, l'id del dispositivo generato non consentirà il monitoraggio del dispositivo tra le app e ottengo un ID univoco per la combinazione app + dispositivo.

È interessante notare che la documentazione di Apple fa riferimento alla convalida delle ricevute del Mac App Store calcolando un hash dell'indirizzo MAC del sistema più l'id del bundle e la versione. Quindi, questo sembra consentito dalla politica, non so ancora se passa attraverso la revisione dell'app.


10
Per evitare la situazione descritta nel secondo punto, imposta l'accessibilità dell'elemento portachiavi su kSecAttrAccessibleAlwaysThisDeviceOnly. Ciò garantirà che l'UUID non venga ripristinato su altri dispositivi, anche se il backup è crittografato.
Jeevan Takhar,

Questo è davvero il comportamento che ho visto molte volte. Ad esempio, registro il mio iPhone per Google Sync. Quindi ho ottenuto un nuovo iPhone, registrarlo e voilà: ora ho 2 iPhone elencati nelle mie impostazioni di sincronizzazione.
Jay Imerman,

11

Sembra per iOS 6, Apple ti consiglia di utilizzare la classe NSUUID .

Dal messaggio ora nei documenti UIDevice per la uniqueIdentifierproprietà:

Obsoleto in iOS 5.0. Utilizzare invece la proprietà identifierForVendor di questa classe o la proprietà advertisingIdentifier della classe ASIdentifierManager, come appropriato, oppure utilizzare il metodo UUID della classe NSUUID per creare un UUID e scriverlo nel database dei valori predefiniti dell'utente.


10

Può essere d'aiuto: utilizzare sotto il codice sarà sempre Unico tranne che per cancellare (Formattare) il dispositivo.

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

1
Ho usato questo codice. Ma quando ho cancellato l'app e di nuovo installato ho ottenuto il nuovo ID
Durgaprasad

1
questa è una soluzione semplice se non hai bisogno di un metodo robusto. lo sto usando nella mia app ora.
Reuben L.

@Durgaprasad: cambierà sempre perché dipende dal fornitore. Ad esempio: 1. Se hai installato un'app con bundleidenedifier: com.abcd.com =>, cambierà. 2. Se hai installato due app con bundleidenedifier: com.abcd.com => Quindi non chnage (mantieni nessuna app durante)
Ashvin Ajadiya,

7

Suggerirei anche di passare uniqueIdentifiera questa libreria open source (2 semplici categorie in realtà) che utilizzano l'indirizzo MAC del dispositivo insieme all'identificatore del pacchetto app per generare un ID univoco nelle applicazioni che può essere utilizzato come sostituto UDID.

Tieni presente che, diversamente dall'UDID, questo numero sarà diverso per ogni app.

Devi semplicemente importare gli inclusi NSStringe le UIDevicecategorie e chiamare in questo [[UIDevice currentDevice] uniqueDeviceIdentifier]modo:

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

Puoi trovarlo su Github qui:

UIDevice con UniqueIdentifier per iOS 5


Ecco le categorie (solo i file .m - controlla il progetto github per le intestazioni):

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
A partire da iOS 7, Apple restituirà un valore costante per l'indirizzo MAC. Ha perfettamente senso. L'indirizzo MAC è sensibile.
Roberto,


4

L'indirizzo MAC può essere falsificato, il che rende tale approccio inutile per legare i contenuti a utenti specifici o implementare funzionalità di sicurezza come le blacklist.

Dopo alcune ulteriori ricerche, mi sembra che non ci siano alternative adeguate al momento. Spero seriamente che Apple riconsidererà la loro decisione.

Forse sarebbe una buona idea inviare un'e-mail a Apple su questo argomento e / o presentare una richiesta di bug / funzionalità su questo dato che forse non sono nemmeno a conoscenza delle conseguenze complete per gli sviluppatori.


13
Un punto valido, tuttavia, credo che l'UUID possa anche essere spoof / swizzled su un telefono jailbreak, quindi tecnicamente l'attuale [UIDevice uniqueIdentifier] è altrettanto imperfetto.
Oliver Pearmain,

3
Puoi sempre creare un identificatore sul server e salvarlo sul dispositivo. Ecco come la maggior parte delle applicazioni lo fanno. Non capisco perché i programmatori iOS abbiano bisogno di qualcosa di speciale.
Sulthan,

1
@Sulthan non funziona su iOS perché se disinstalli un'app tutti i suoi dati sono spariti, quindi non c'è modo di garantire un identificatore univoco del dispositivo in quel modo.
Lkraider,

4
Non se lo salvi sul portachiavi. Comunque, non ho mai visto un'app in cui questo fosse un problema. Se l'app e i dati sono stati eliminati, non è necessario lo stesso identificativo del dispositivo. Se desideri identificare l'utente, chiedigli di inviare un'e-mail.
Sulthan,

Apple ha inoltre vietato l'accesso agli indirizzi MAC nella nuova versione di iOS;
Ans

4

UIDevice identifierForVendor introdotto in iOS 6 funzionerebbe per i tuoi scopi.

identifierForVendorè una stringa alfanumerica che identifica in modo univoco un dispositivo per il fornitore dell'app. (sola lettura)

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

Il valore di questa proprietà è lo stesso per le app che provengono dallo stesso fornitore in esecuzione sullo stesso dispositivo. Viene restituito un valore diverso per le app sullo stesso dispositivo che provengono da fornitori diversi e per le app su dispositivi diversi per quanto riguarda il fornitore.

Disponibile in iOS 6.0 e versioni successive e dichiarato in UIDevice.h

Per iOS 5 fai riferimento a questo link UIDevice-with-UniqueIdentifier-for-iOS-5


4

Utilizzando la SSKeychain e il codice sopra menzionato. Ecco il codice da copiare / incollare (aggiungi il modulo 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

Il seguente codice aiuta a ottenere l'UDID:

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

3

Questo è il codice che sto usando per ottenere l'ID sia per iOS 5 che per 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];
}

Cosa fai riguardo l'avvertimento del compilatore PerformSelector may cause a leak because its selector is unknown?
Basil Bourque,

Non è più possibile utilizzare advertisingIdentifier per questo scopo poiché Apple lo rifiuterà. Maggiori informazioni: techcrunch.com/2014/02/03/...
codeplasma


2

iOS 11 ha introdotto il framework DeviceCheck. Ha una soluzione completa per identificare in modo univoco il dispositivo.


1

Un modo di lavorare per ottenere UDID:

  1. Avvia un server Web all'interno dell'app con due pagine: una dovrebbe restituire il profilo MobileConfiguration appositamente predisposto e un'altra dovrebbe raccogliere l'UDID. Maggiori informazioni qui , qui e qui .
  2. Apri la prima pagina in Mobile Safari dall'interno dell'app e ti reindirizza a Settings.app chiedendo di installare il profilo di configurazione. Dopo aver installato il profilo, UDID viene inviato alla seconda pagina Web e puoi accedervi dall'interno dell'app. (Settings.app ha tutti i diritti necessari e diverse regole sandbox).

Un esempio che utilizza 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)
    }
}

Ecco i contenuti di 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>

L'installazione del profilo fallirà (non mi sono preoccupato di implementare una risposta prevista, consultare la documentazione ), ma l'app otterrà un UDID corretto. E dovresti anche firmare il mobileconfig .


1

Per Swift 3.0, utilizzare il codice seguente.

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

1
iOS 11 ha introdotto il framework DeviceCheck. Ha una soluzione completa per identificare in modo univoco il dispositivo.
Santosh Botre,

1

Puoi usare

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

Che è unico per il dispositivo in tutte le applicazioni.



0

Se qualcuno si imbatte in questa domanda, quando cerca un'alternativa. Ho seguito questo approccio in IDManagerclasse, questa è una raccolta di diverse soluzioni. KeyChainUtil è un wrapper da leggere dal portachiavi. Puoi anche usare il hashed MAC addresstipo di ID univoco.

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

Possiamo usare identifierForVendor per 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;
}

--Nota importante ---

UDID e identificatoreForVendor sono diversi: ---

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.

sei sicuro ? possiamo usare identifierForVendor per iOS7?
Avis,

0

Apple ha nascosto l'UDID da tutte le API pubbliche, a partire da iOS 7. Qualsiasi UDID che inizia con FFFF è un ID falso. Le app "Invia UDID" che in precedenza funzionavano non possono più essere utilizzate per raccogliere UDID per dispositivi di test. (sospiro!)

L'UDID viene visualizzato quando un dispositivo è collegato a XCode (nell'organizzatore) e quando il dispositivo è collegato a iTunes (anche se è necessario fare clic su "Numero di serie" per visualizzare l'identificatore.

Se devi ottenere l'UDID per un dispositivo da aggiungere a un profilo di provisioning e non puoi farlo tu stesso in XCode, dovrai seguirli attraverso i passaggi per copiarlo / incollarlo da iTunes.

C'è un modo da (rilascio di iOS 7) per ottenere l'UDID senza usare iTunes su un PC / Mac?


0

Ho avuto anche qualche problema e la soluzione è semplice:

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

Un'alternativa non perfetta ma una delle migliori e più vicine all'UDID (in Swift usando iOS 8.1 e Xcode 6.1):

Generazione di un UUID casuale

let strUUID: String = NSUUID().UUIDString

E usa la libreria KeychainWrapper :

Aggiungi un valore di stringa al portachiavi:

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

Recupera un valore di stringa dal portachiavi:

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

Rimuovi un valore di stringa dal portachiavi:

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

Questa soluzione utilizza il portachiavi, quindi il record memorizzato nel portachiavi sarà persistente, anche dopo che l'app è stata disinstallata e reinstallata. L'unico modo per eliminare questo record è ripristinare tutti i contenuti e le impostazioni del dispositivo. Ecco perché ho detto che questa soluzione di sostituzione non è perfetta, ma rimane una delle migliori soluzioni di sostituzione di UDID su iOS 8.1 usando Swift.


0

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.