UIDevice uniqueIdentifier veraltet - Was ist jetzt zu tun?


501

Es hat sich gerade herausgestellt, dass die Eigenschaft uniqueIdentifier von UIDevice in iOS 5 veraltet und in iOS 7 und höher nicht verfügbar ist. Es scheint keine alternative Methode oder Eigenschaft verfügbar oder verfügbar zu sein.

Viele unserer vorhandenen Apps sind stark von dieser Eigenschaft abhängig, um ein bestimmtes Gerät eindeutig zu identifizieren. Wie könnten wir dieses Problem in Zukunft behandeln?

Der Vorschlag aus der Dokumentation in 2011-2012 war:

Besondere Überlegungen

Verwenden Sie nicht die Eigenschaft uniqueIdentifier. Um eine eindeutige Kennung für Ihre App CFUUIDCreatezu erstellen , können Sie die Funktion zum Erstellen einer Kennung aufrufen UUIDund diese mithilfe der NSUserDefaultsKlasse in die Standarddatenbank schreiben .

Dieser Wert ist jedoch nicht identisch, wenn ein Benutzer die App deinstalliert und neu installiert.


1
Für Apps, die noch uniqueIdentifier verwenden, gibt iOS7 jetzt FFFFFFFF + identifierForVendor zurück, wodurch viele schlecht geschriebene, nicht erneuerbare Abonnement-Apps beschädigt werden.
Rhythmic Fistman

Wenn Ihre App zum Glück Push-Benachrichtigungen verwendet, können Sie das Token verwenden, das vom Push-Service von Apple zurückgesendet wurde. Es ist auch pro Gerät einzigartig
Calin Chitu,

@CalinChitu Wenn der Benutzer keine Push-Benachrichtigungen akzeptiert, erhalten Sie trotzdem eine Push-ID für diesen Benutzer?
Chase Roberts

Antworten:


272

Eine von erstellte UUID CFUUIDCreate ist eindeutig, wenn ein Benutzer die App deinstalliert und neu installiert: Sie erhalten jedes Mal eine neue.

Möglicherweise möchten Sie jedoch, dass es nicht eindeutig ist, dh, es sollte gleich bleiben, wenn der Benutzer die App deinstalliert und neu installiert. Dies erfordert ein wenig Aufwand, da die MAC-Adresse die zuverlässigste Kennung pro Gerät zu sein scheint. Sie können den MAC abfragen und als UUID verwenden.

Bearbeiten: Man muss natürlich immer den MAC derselben Schnittstelle abfragen. Ich denke, die beste Wette ist mit en0. Der MAC ist immer vorhanden, auch wenn die Schnittstelle keine IP hat / nicht verfügbar ist.

Bearbeiten 2: Wie von anderen erwähnt, ist die bevorzugte Lösung seit iOS 6 - [UIDevice identifierForVendor] . In den meisten Fällen sollten Sie es als Ersatz für die alte verwenden können -[UIDevice uniqueIdentifier](aber eine UUID, die beim ersten Start der App erstellt wird, scheint von Apple gewünscht zu werden).

Bearbeiten 3: Damit dieser wichtige Punkt nicht im Kommentarrauschen verloren geht: Verwenden Sie den MAC nicht als UUID, sondern erstellen Sie einen Hash mit dem MAC . Dieser Hash führt jedes Mal zum gleichen Ergebnis, auch bei Neuinstallationen und Apps (wenn das Hashing auf die gleiche Weise durchgeführt wird). Heutzutage (2013) ist dies nicht mehr erforderlich, es sei denn, Sie benötigen eine "stabile" Gerätekennung unter iOS <6.0.

Bearbeiten 4: In iOS 7 gibt Apple jetzt immer einen festen Wert zurück, wenn der MAC abgefragt wird, um den MAC als Basis für ein ID- Schema gezielt zu vereiteln . Sie sollten jetzt also wirklich - [UIDevice identifierForVendor] verwenden oder eine UUID pro Installation erstellen.


8
Ändert sich die Mac-Adresse nicht, je nachdem, ob der Benutzer über WLAN verbunden ist oder nicht?
Oliver Pearmain

1
@DarkDust: Da sich jedoch die aktive Schnittstelle ändert, wenn Sie von WLAN zu Mobilfunkmodem wechseln, sollte sich auch die MAC-Adresse der aktiven Schnittstelle ändern. es sei denn, Sie wählen immer eine bestimmte Schnittstelle, um den MAC zu erhalten
user102008

3
@ Roger Nolan: Bitte bearbeiten Sie nicht die Antworten anderer Leute und fügen Sie Dinge hinzu, die aussehen, als stammten sie vom ursprünglichen Autor. Vielen Dank.
DarkDust

2
@RogerNolan Solange der Beitrag keine Community-Antwort ist, dienen die Änderungen dazu, Fehler und dergleichen zu korrigieren und keine neuen Inhalte hinzuzufügen. Es gibt einen Grund, warum Sie sich das Privileg verdient haben. Stellen Sie sich vor, ich bearbeite Ihre Antwort und schreibe etwas BS. Die Leute würden denken, Sie hätten das geschrieben. Ich bezweifle, dass dir das gefallen würde :-) Aber du wirst nicht benachrichtigt, dass eine Bearbeitung stattgefunden hat, ich habe es nur zufällig herausgefunden.
DarkDust

3
Apple lehnt jetzt Apps ab, die Hash-MAC verwenden.
Idan

91

Sie können Ihre Alternative bereits für Apple verwenden UDID. Freundlicher Kerl gekitz schrieb eine Kategorie, auf UIDeviceder eine Art UDIDbasierend auf der Mac-Adresse des Geräts und der Bundle- ID generiert wird .

Sie finden Code auf Github


3
Diese Implementierung ist eindeutig (MAC-Adresse) für ein Gerät über Neuinstallationen hinweg, wie z. B. die uniqueId von Apple, respektiert jedoch auch den Datenschutz und ist auch für eine Anwendung eindeutig (verwenden Sie auch bundleId) ... Ein Muss, das Apple in seine APIs aufnehmen sollte. .. anstatt ohne Alternativen zu verwerfen.
Vincent Guerci

8
Obwohl es die alte bsd-Lizenz mit der Werbeklausel verwendet, yuck.
jbtule

8
Für alle anderen, die diesen Beitrag jetzt finden, wurde die Lizenz seit dem obigen Kommentar von jbtule geändert.
James

1
Wie in diesem Commit-Kommentar besprochen, stellt die Bibliothek im Ist-Zustand ein ernstes Datenschutzproblem dar und sollte nicht verwendet werden:
Wird

15
Ab iOS 7 gibt das System den Wert immer zurück, 02:00:00:00:00:00wenn Sie auf einem beliebigen Gerät nach der MAC-Adresse fragen. Überprüfen Sie hier: developer.apple.com/library/prerelease/ios/releasenotes/General/…
Hejazi

61

Basierend auf dem von @moonlight vorgeschlagenen Link habe ich mehrere Tests durchgeführt und es scheint die beste Lösung zu sein. Wie @DarkDust sagt, überprüft en0die Methode, welche immer verfügbar ist.
Es gibt zwei Optionen:
uniqueDeviceIdentifier(MD5 von MAC + CFBundleIdentifier)
und uniqueGlobalDeviceIdentifier(MD5 von MAC), diese geben immer die gleichen Werte zurück.
Unter den Tests, die ich durchgeführt habe (mit dem realen Gerät):

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

XXXX21f1f19edff198e2a2356bf4XXXX - (Wi-Fi) nach dem Entfernen und erneuten Installieren der App XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) nach dem Entfernen und Installieren der App

Hoffe es ist nützlich.

BEARBEITEN:
Wie andere betonten, ist diese Lösung in iOS 7 nicht mehr nützlich, da sie uniqueIdentifiernicht mehr verfügbar ist und die Abfrage der MAC-Adresse jetzt immer 02: 00: 00: 00: 00: 00 zurückgibt


13
Dies funktioniert unter iOS7 nicht. Apple eliminiert die Verwendung der MAC-Adresse.
Sarim Sidd

@SarimSidd Derzeit liegen Informationen zu iOS 7 unter NDA, die wir hier nicht diskutieren können.
Mat

57

Schau dir das an,

Wir können Schlüsselbund anstelle von NSUserDefaultsKlasse verwenden, um von UUIDerstellte zu speichern CFUUIDCreate.

Auf diese Weise könnten wir UUIDbei einer Neuinstallation eine Neuerstellung vermeiden und UUIDfür dieselbe Anwendung immer dasselbe erhalten, selbst wenn der Benutzer deinstalliert und erneut installiert.

UUID wird nur neu erstellt, wenn das Gerät vom Benutzer zurückgesetzt wird.

Ich habe diese Methode mit SFHFKeychainUtils ausprobiert und sie funktioniert wie ein Zauber.


33
Diese Methode ist ein solider Ersatz für UDID. Es hat auch den zusätzlichen Vorteil, dass die Kennung nach dem Geräteformat neu erstellt wird (z. B. wenn das Gerät den Besitzer wechselt). Es ist jedoch wichtig zu beachten, dass der Schlüsselbund auf anderen Geräten wiederhergestellt werden kann, wenn der Benutzer seine Sicherung verschlüsselt. Dies kann dazu führen, dass mehrere Geräte dieselbe UUID verwenden. Um dies zu vermeiden, setzen Sie die Zugänglichkeit Ihres Schlüsselbundelements auf kSecAttrAccessibleAlwaysThisDeviceOnly. Dadurch wird sichergestellt, dass Ihre UUID nicht auf ein anderes Gerät migriert wird. Verwenden Sie den kSecAttrAccessGroupSchlüssel , um von anderen Apps aus auf Ihre UUID zuzugreifen .
Jeevan Takhar

Wo genau (mit welchem ​​Schlüssel) sollen Sie die UUID im Schlüsselbund speichern?
Verlorene Übersetzung

Opps! Link ist defekt
COVID19

48

Erstellen Sie Ihre eigene UUID und speichern Sie sie im Schlüsselbund. Somit bleibt es auch dann bestehen, wenn Ihre App deinstalliert wird. In vielen Fällen bleibt es auch dann bestehen, wenn der Benutzer zwischen Geräten migriert (z. B. vollständige Sicherung und Wiederherstellung auf einem anderen Gerät).

Tatsächlich wird es für Sie zu einer eindeutigen Benutzer- ID. (sogar besser als Gerätekennung ).

Beispiel:

Ich definiere eine benutzerdefinierte Methode zum Erstellen eines UUIDals:

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

Sie können es dann KEYCHAINbeim ersten Start Ihrer App speichern . Damit wir es nach dem ersten Start einfach über den Schlüsselbund verwenden können, müssen wir es nicht neu generieren. Der Hauptgrund für die Verwendung des Schlüsselbunds zum Speichern ist: Wenn Sie UUIDden Schlüsselbund festlegen, bleibt er auch dann bestehen, wenn der Benutzer die App vollständig deinstalliert und anschließend erneut installiert. . Dies ist also die permanente Art der Speicherung, was bedeutet, dass der Schlüssel vollständig eindeutig ist.

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

Geben Sie beim Start der Anwendung den folgenden Code an:

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

Laden Sie die Dateien SSKeychain.m und .h von sskeychain herunter und ziehen Sie die Dateien SSKeychain.m und .h in Ihr Projekt. Fügen Sie Ihrem Projekt "Security.framework" hinzu. Um die UUID anschließend zu verwenden, verwenden Sie einfach:

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

Da ein identifierForVendor funktioniert, ist dies nicht perfekt. In einigen Fällen kann eine Null oder 0x0 zurückgegeben werden. Diese Methode scheint perfekt zu funktionieren
CReaTuS

3
Hat jemand bestätigt, dass dies unter iOS7 funktioniert, nachdem der Zyklus deinstalliert / neu installiert und die Apple App überprüft wurde?
Mindbomb

Ich habe angefangen, diese Lösung zu verwenden. Mehrere Tests auf 2 Geräten (Neuaufbau, Neuinstallation, Herunterfahren des Geräts) haben gezeigt, dass die ID identisch ist. iOS 10.3.
Deko

16

Vielleicht können Sie verwenden:

[UIDevice currentDevice].identifierForVendor.UUIDString

In der Dokumentation von Apple wird identifierForVender wie folgt beschrieben:

Der Wert dieser Eigenschaft ist für Apps gleich, die von demselben Anbieter stammen, der auf demselben Gerät ausgeführt wird. Für Apps auf demselben Gerät, die von verschiedenen Anbietern stammen, und für Apps auf verschiedenen Geräten, unabhängig vom Anbieter, wird ein anderer Wert zurückgegeben.


Neugierig, warum bis vor kurzem niemand darüber gesprochen hat ... Und jetzt sehe ich, dass es mit iOS 6 neu ist.
James Boutcher

1
Wenn der Benutzer ios aktualisiert und / oder neue ios installiert, ändert sich der Wert von identifierForVendor oder bleibt er gleich?
Sunil Zalavadiya

1
Nachdem Sie alle Apps vom selben Anbieter entfernt haben, wird dieser Wert geändert.
Mitesh Khatri

14

Möglicherweise möchten Sie in Betracht ziehen, OpenUDIDeinen Ersatz für die veralteten zu verwenden UDID.

Grundsätzlich sind UDIDfolgende Funktionen erforderlich, um die Anforderungen zu erfüllen:

  1. eindeutig oder ausreichend eindeutig (eine Kollision mit geringer Wahrscheinlichkeit ist wahrscheinlich sehr akzeptabel)
  2. Persistenz über Neustarts, Wiederherstellungen und Deinstallationen hinweg
  3. verfügbar für Apps verschiedener Anbieter (nützlich, um Benutzer über CPI-Netzwerke zu gewinnen) -

OpenUDID erfüllt die oben genannten Anforderungen und verfügt sogar über einen integrierten Opt-Out-Mechanismus für spätere Überlegungen.

Überprüfen Sie http://OpenUDID.org, es zeigt auf den entsprechenden GitHub. Hoffe das hilft!

Als Randnotiz würde ich jede MAC-Adressalternative scheuen. Während die MAC-Adresse wie eine verlockende und universelle Lösung erscheint, stellen Sie sicher, dass diese niedrig hängende Frucht vergiftet ist. Die MAC-Adresse ist sehr vertraulich, und Apple kann den Zugriff auf diese Adresse möglicherweise ablehnen, bevor Sie überhaupt "DIESE APP SENDEN" sagen können. Die MAC-Netzwerkadresse wird zur Authentifizierung bestimmter Geräte in privaten LANs (WLANs) oder anderen virtuellen privaten Netzwerken verwendet Netzwerke (VPNs). .. es ist noch empfindlicher als die frühere UDID!


Ich bin wirklich neugierig, wie das funktioniert? Der Code ist in Objective-C geschrieben, aber es gibt keine andere gute Lösung, die den oben genannten Anforderungen entspricht. Was unterscheidet dieses Framework also? Die Lösung, die dieses Framework verwendet, sollte auch als vorgeschlagene Antwort hier veröffentlicht werden können ...
jake_hetfield

Ich stimme zu - die MAC-Adresse kann auch manuell konfiguriert werden ("geklont"), obwohl dies größtenteils nicht wahrscheinlich ist. Ich muss gegen das D in UDID protestieren. Dies ist keine Geräte-ID, sondern eine UUID (Universally Unique Identifier). Die Geräte-ID wird von Apple ab Werk auf jedem Gerät im ROM abgestempelt.
Jay Imerman

Die beste Lösung für iOS7 ist auch das, was tatsächlich benötigt wird, um ein Gerät eindeutig zu identifizieren
vishal dharankar

1
OpenUDID ist veraltet und wird nicht empfohlen
mkll

11

Ich bin sicher, Apple hat viele Leute mit dieser Änderung geärgert. Ich entwickle eine Buchhaltungs-App für iOS und habe einen Onlinedienst zum Synchronisieren von Änderungen, die auf verschiedenen Geräten vorgenommen wurden. Der Dienst verwaltet eine Datenbank aller Geräte und der Änderungen, die an diese weitergegeben werden müssen. Daher ist es wichtig zu wissen, welche Geräte welche sind. Ich verfolge Geräte mit dem UIDevice uniqueIdentifier und für das, was es wert ist, sind hier meine Gedanken.

  • Eine UUID generieren und in den Benutzerstandards speichern? Nicht gut, da dies nicht anhält, wenn der Benutzer die App löscht. Wenn sie später erneut installiert werden, sollte der Onlinedienst keinen neuen Gerätedatensatz erstellen, da dies Ressourcen auf dem Server verschwenden und eine Liste von Geräten erstellen würde, die zwei oder mehr Mal dasselbe enthalten. Benutzer würden mehr als ein "Bob's iPhone" aufgelistet sehen, wenn sie die App neu installieren würden.

  • Eine UUID generieren und im Schlüsselbund speichern? Dies war mein Plan, da er auch dann bestehen bleibt, wenn die App deinstalliert wird. Beim Wiederherstellen eines iTunes-Backups auf einem neuen iOS-Gerät wird der Schlüsselbund jedoch übertragen, wenn das Backup verschlüsselt ist. Dies kann dazu führen, dass zwei Geräte dieselbe Geräte-ID enthalten, wenn sowohl das alte als auch das neue Gerät in Betrieb sind. Diese sollten im Onlinedienst als zwei Geräte aufgeführt werden, auch wenn der Gerätename identisch ist.

  • Einen Hash der MAC-Adresse und der Bundle-ID generieren? Dies scheint die beste Lösung für das zu sein, was ich brauche. Durch Hashing mit der Bundle-ID kann das Gerät aufgrund der generierten Geräte-ID nicht über Apps hinweg verfolgt werden, und ich erhalte eine eindeutige ID für die Kombination aus App und Gerät.

Es ist interessant festzustellen, dass sich Apples eigene Dokumentation auf die Validierung von Mac App Store-Belegen bezieht, indem ein Hash der System-MAC-Adresse sowie die Bundle-ID und -Version berechnet werden. Dies scheint also aus politischen Gründen zulässig zu sein, ob es eine App-Überprüfung durchläuft, die ich noch nicht kenne.


10
Um die in Ihrem zweiten Punkt beschriebene Situation zu vermeiden, setzen Sie die Zugänglichkeit Ihres Schlüsselbundelements auf kSecAttrAccessibleAlwaysThisDeviceOnly. Dadurch wird sichergestellt, dass Ihre UUID nicht auf anderen Geräten wiederhergestellt wird, selbst wenn die Sicherung verschlüsselt ist.
Jeevan Takhar

Dies ist in der Tat das Verhalten, das ich oft gesehen habe. Zum Beispiel registriere ich mein iPhone für Google Sync. Dann habe ich ein neues iPhone bekommen, es registriert und voila - ich habe jetzt 2 iPhones in meinen Synchronisierungseinstellungen aufgelistet.
Jay Imerman

11

Es sieht so aus, als würde Apple für iOS 6 die Verwendung der NSUUID-Klasse empfehlen .

Aus der Nachricht jetzt in den UIDevice- Dokumenten für uniqueIdentifierEigenschaft:

In iOS 5.0 veraltet. Verwenden Sie stattdessen die identifierForVendor-Eigenschaft dieser Klasse oder die AdvertisingIdentifier-Eigenschaft der ASIdentifierManager-Klasse, oder verwenden Sie die UUID-Methode der NSUUID-Klasse, um eine UUID zu erstellen und in die Benutzerstandarddatenbank zu schreiben.


10

Kann helfen: Verwenden Sie den folgenden Code, der immer eindeutig ist, außer wenn Sie Ihr Gerät löschen (formatieren).

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

1
Ich habe diesen Code verwendet. Aber als ich die App löschte und erneut installierte, bekam ich eine neue
ID

1
Dies ist eine einfache Lösung, wenn Sie keine robuste Methode benötigen. Ich benutze es jetzt in meiner App.
Reuben L.

@ Durgaprasad: Es wird sich immer ändern, da es vom Anbieter abhängt. Zum Beispiel: 1. Wenn Sie eine App mit bundleidenedifier installiert haben: com.abcd.com =>, ändert sich diese. 2. Wenn Sie zwei Apps mit Bundleidenedifier installiert haben: com.abcd.com => Dann wird es nicht geändert (behalten Sie eine App während)
Ashvin Ajadiya

7

Ich würde auch über empfehlen Wechsel uniqueIdentifierzu dieser Open - Source - Bibliothek (2 einfache Kategorien wirklich) , dass das Geräts der MAC - Adresse zusammen mit dem App Bundle Identifier verwendet eine eindeutige ID in Ihren Anwendungen zu erzeugen , die als UDID Ersatz verwendet werden können.

Beachten Sie, dass diese Nummer im Gegensatz zur UDID für jede App unterschiedlich ist.

Sie müssen lediglich die enthaltenen NSStringund UIDeviceKategorien importieren und [[UIDevice currentDevice] uniqueDeviceIdentifier]wie folgt aufrufen :

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

Sie finden es auf Github hier:

UIDevice mit UniqueIdentifier für iOS 5


Hier sind die Kategorien (nur die .m-Dateien - überprüfen Sie das Github-Projekt auf die Header):

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
Ab iOS 7 gibt Apple einen konstanten Wert für die MAC-Adresse zurück. Es macht vollkommen Sinn. Die MAC-Adresse ist vertraulich.
Roberto


4

Die MAC-Adresse kann gefälscht werden, wodurch ein solcher Ansatz unbrauchbar wird, um Inhalte an bestimmte Benutzer zu binden oder Sicherheitsfunktionen wie Blacklists zu implementieren.

Nach einigen weiteren Nachforschungen scheint es mir, dass wir ab sofort keine richtige Alternative mehr haben. Ich hoffe ernsthaft, dass Apple ihre Entscheidung überdenken wird.

Vielleicht wäre es eine gute Idee, Apple eine E-Mail zu diesem Thema zu senden und / oder eine Fehler- / Funktionsanfrage zu diesem Thema einzureichen, da sie möglicherweise nicht einmal die vollständigen Konsequenzen für Entwickler kennen.


13
Ein gültiger Punkt, aber ich glaube, dass die UUID auch auf einem Telefon mit Jailbreak gefälscht / durchgespielt werden kann, so dass der vorhandene [UIDevice uniqueIdentifier] technisch genauso fehlerhaft ist.
Oliver Pearmain

3
Sie können jederzeit eine Kennung auf dem Server erstellen und auf dem Gerät speichern. So machen es die meisten Anwendungen. Ich verstehe nicht, warum iOS-Programmierer etwas Besonderes brauchen.
Sulthan

1
@Sulthan funktioniert unter iOS nicht, da bei der Deinstallation einer App alle Daten verloren gehen. Auf diese Weise kann keine eindeutige Gerätekennung garantiert werden.
lkraider

4
Nicht, wenn Sie es im Schlüsselbund speichern. Wie auch immer, ich habe noch nie eine App gesehen, bei der dies ein Problem war. Wenn die App und die Daten gelöscht wurden, benötigen Sie nicht dieselbe Gerätekennung. Wenn Sie den Benutzer identifizieren möchten, fragen Sie ihn nach einer E-Mail.
Sulthan

Der Zugriff auf MAC-Adressen wurde von Apple in der neuen Version von iOS ebenfalls gesperrt.
Ans

4

UIDevice identifierForVendor in iOS 6 eingeführt würde für Ihre Zwecke funktionieren.

identifierForVendorist eine alphanumerische Zeichenfolge, die ein Gerät gegenüber dem Anbieter der App eindeutig identifiziert. (schreibgeschützt)

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

Der Wert dieser Eigenschaft ist für Apps gleich, die von demselben Anbieter stammen, der auf demselben Gerät ausgeführt wird. Für Apps auf demselben Gerät, die von verschiedenen Anbietern stammen, und für Apps auf verschiedenen Geräten, die vom Anbieter stammen, wird ein anderer Wert zurückgegeben.

Verfügbar in iOS 6.0 und höher und deklariert in UIDevice.h

Für iOS 5 siehe diesen Link UIDevice-with-UniqueIdentifier-for-iOS-5


4

Verwendung der oben genannten SSKeychain und des Codes. Hier ist Code zum Kopieren / Einfügen (SSKeychain-Modul hinzufügen):

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

Der folgende Code hilft beim Abrufen der UDID:

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

3

Dies ist der Code, mit dem ich die ID für iOS 5 und iOS 6, 7 erhalte:

- (NSString *) advertisingIdentifier
{
    if (!NSClassFromString(@"ASIdentifierManager")) {
        SEL selector = NSSelectorFromString(@"uniqueIdentifier");
        if ([[UIDevice currentDevice] respondsToSelector:selector]) {
            return [[UIDevice currentDevice] performSelector:selector];
        }
    }
    return [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
}

Was tun Sie gegen die Compiler-Warnung PerformSelector may cause a leak because its selector is unknown?
Basil Bourque

Sie können AdvertisingIdentifier für diesen Zweck nicht mehr verwenden, da Apple dies ablehnt. Weitere Informationen: techcrunch.com/2014/02/03/…
Codeplasma


2

iOS 11 hat das DeviceCheck-Framework eingeführt. Es verfügt über eine vollständige Lösung zur eindeutigen Identifizierung des Geräts.


1

Ein funktionierender Weg, um UDID zu erhalten:

  1. Starten Sie einen Webserver in der App mit zwei Seiten: Eine sollte ein speziell gestaltetes MobileConfiguration-Profil zurückgeben und eine andere sollte die UDID erfassen. Mehr Infos hier , hier und hier .
  2. Sie öffnen die erste Seite in Mobile Safari in der App und werden zu Settings.app weitergeleitet, wo Sie aufgefordert werden, das Konfigurationsprofil zu installieren. Nach der Installation des Profils wird die UDID an die zweite Webseite gesendet und Sie können über die App darauf zugreifen. (Settings.app verfügt über alle erforderlichen Berechtigungen und unterschiedliche Sandbox-Regeln).

Ein Beispiel mit 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)
    }
}

Hier sind die Inhalte von 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>

Die Profilinstallation schlägt fehl (ich habe mich nicht darum gekümmert, eine erwartete Antwort zu implementieren, siehe Dokumentation ), aber die App erhält eine korrekte UDID. Und Sie sollten auch die mobileconfig unterschreiben .


1

Für Swift 3.0 verwenden Sie bitte den folgenden Code.

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

1
iOS 11 hat das DeviceCheck-Framework eingeführt. Es verfügt über eine vollständige Lösung zur eindeutigen Identifizierung des Geräts.
Santosh Botre

1

Sie können verwenden

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

Welches ist für das Gerät in allen Anwendungen einzigartig.



0

Wenn jemand auf diese Frage stößt, wenn er nach einer Alternative sucht. Ich habe diesen Ansatz im IDManagerUnterricht verfolgt. Dies ist eine Sammlung verschiedener Lösungen. KeyChainUtil ist ein Wrapper zum Lesen aus dem Schlüsselbund. Sie können die hashed MAC addressID auch als eine Art eindeutige ID verwenden.

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

Wir können identifierForVendor für ios7 verwenden,

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

--Wichtige Notiz ---

UDID und identifierForVendor unterscheiden sich: ---

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.

bist du sicher ? können wir identifierForVendor für ios7 verwenden?
Avis

0

Apple hat die UDID ab iOS 7 vor allen öffentlichen APIs verborgen. Jede UDID, die mit FFFF beginnt, ist eine gefälschte ID. Die zuvor funktionierenden "UDID senden" -Apps können nicht mehr zum Sammeln von UDIDs für Testgeräte verwendet werden. (Seufzer!)

Die UDID wird angezeigt, wenn ein Gerät mit XCode verbunden ist (im Organizer) und wenn das Gerät mit iTunes verbunden ist (obwohl Sie auf "Seriennummer" klicken müssen, um die Kennung anzuzeigen.

Wenn Sie die UDID für ein Gerät zum Hinzufügen zu einem Bereitstellungsprofil benötigen und dies in XCode nicht selbst tun können, müssen Sie sie durch die Schritte zum Kopieren / Einfügen aus iTunes führen.

Gibt es seit (Veröffentlichung von iOS 7) eine Möglichkeit, die UDID zu erhalten, ohne iTunes auf einem PC / Mac zu verwenden?


0

Ich hatte auch ein Problem und die Lösung ist einfach:

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

Eine nicht perfekte, aber eine der besten und am nächsten gelegenen Alternativen zu UDID (in Swift mit iOS 8.1 und Xcode 6.1):

Generieren einer zufälligen UUID

let strUUID: String = NSUUID().UUIDString

Und verwenden Sie die KeychainWrapper- Bibliothek:

Fügen Sie dem Schlüsselbund einen Zeichenfolgenwert hinzu:

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

Rufen Sie einen Zeichenfolgenwert aus dem Schlüsselbund ab:

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

Entfernen Sie einen Zeichenfolgenwert aus dem Schlüsselbund:

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

Diese Lösung verwendet den Schlüsselbund, sodass der im Schlüsselbund gespeicherte Datensatz auch nach der Deinstallation und Neuinstallation der App erhalten bleibt. Die einzige Möglichkeit, diesen Datensatz zu löschen, besteht darin, alle Inhalte und Einstellungen des Geräts zurückzusetzen. Aus diesem Grund habe ich erwähnt, dass diese Substitutionslösung nicht perfekt ist, sondern eine der besten Lösungen für den Ersatz von UDID unter iOS 8.1 mit Swift bleibt.


0

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.