unikalny identyfikator użytkownika iOS [duplikat]

To pytanie ma już odpowiedź tutaj:

Piszę aplikację na iphone ' a, która komunikuje się z moim serwerem za pomocą REST. Główny problem polega na tym, że muszę jakoś zidentyfikować użytkownika. Nie tak dawno temu pozwolono nam używać UDID, ale teraz nie jest już dozwolone. Co z tego? powinienem użyć zamiast tego? Potrzebuję jakiegoś identyfikatora na iPhonie, więc użytkownik usunie aplikację, zainstaluje ją ponownie i otrzyma ten sam IDENTYFIKATOR.

Author: S.Lott, 2011-09-01

7 answers

Po pierwsze, UDID jest tylko przestarzały w iOS 5. To nie znaczy, że zniknął (jeszcze).

Po drugie, powinieneś zadać sobie pytanie, czy naprawdę potrzebujesz czegoś takiego. Co jeśli użytkownik otrzyma nowe urządzenie i zainstaluje na nim aplikację? Ten sam użytkownik, ale UDID się zmienił. Tymczasem oryginalny użytkownik mógł sprzedać swoje stare urządzenie, więc teraz zupełnie nowy użytkownik instaluje Twoją aplikację i myślisz, że to inna osoba oparta na UDID.

Jeśli nie potrzebujesz UDID, użyj CFUUIDCreate(), aby Utwórz unikalny identyfikator i zabezpiecz go domyślnym użytkownikowi przy pierwszym uruchomieniu(użyj CFUUIDCreateString(), Aby przekonwertować uuid na ciąg znaków). Przetrwa kopie zapasowe i przywraca, a nawet pojawi się wraz z oryginalnym użytkownikiem, gdy przełączy się na nowe urządzenie. To pod wieloma względami lepsza opcja niż UDID.

Jeśli naprawdę potrzebujesz unikalnego identyfikatora urządzenia (nie brzmi to tak, jak ty), wybierz adres MAC, jak wskazano w odpowiedzi Suhaila.

 67
Author: Ole Begemann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-01 17:32:42

Użyłem CFUUIDCreate() Aby utworzyć UUID:

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

Następnie Ustaw powyższy UUID na mój NSString:

NSString *UUID = [nameofclasswhereGetUUIDclassmethodresides UUID];

Następnie zapisałem ten UUID do pęku kluczy za pomocą SSKeyChain

Aby ustawić UUID za pomocą SSKeyChain:

[SSKeychain setPassword:UUID forService:@"com.yourapp.yourcompany" account:@"user"];

Aby go odzyskać:

NSString *retrieveuuid = [SSKeychain passwordForService:@"com.yourapp.yourcompany" account:@"user"];

Po ustawieniu identyfikatora uuid na pęku kluczy, będzie on trwał, nawet jeśli użytkownik całkowicie odinstaluje aplikację, a następnie zainstaluje ją ponownie.

Aby upewnić się, że wszystkie urządzenia mają ten sam UUID w Pęku Kluczy.

  1. skonfiguruj aplikację do korzystania z iCloud.
  2. Zapisz UUID, który jest w Pęku Kluczy, również do NSUserDefaults.
  3. przekazuje UUID w NSUserDefaults do chmury z przechowywaniem danych o wartości klucza.
  4. przy pierwszym uruchomieniu aplikacji Sprawdź, czy dane w chmurze są dostępne i ustaw UUID w Pęku Kluczy na nowym urządzeniu.

Masz teraz unikalny identyfikator, który jest trwały i współdzielony/zsynchronizowany ze wszystkimi urządzeniami.

 185
Author: Moomio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-22 15:32:05

Aktualizowałem moją aplikację, która działała tylko w oparciu o unikalny identyfikator, który obsługiwał iOS 4.3 i nowsze. więc,

1) nie mogłem użyć [UIDevice currentDevice].uniqueIdentifier; ponieważ nie było już dostępne

2) nie mogłem używać [UIDevice currentDevice].identifierForVendor.UUIDString, ponieważ był on dostępny tylko w iOS 6.0 i późniejszych i nie był w stanie korzystać z niższych wersji iOS.

Adres mac nie był opcją, ponieważ nie był dozwolony w iOS-7

4) OpenUDID był przestarzały jakiś czas temu i miał również problemy z iOS-6.

5) identyfikatory reklam nie były również dostępne dla iOS-5 i poniżej

W końcu to właśnie zrobiłem

A) dodano SFHFKeychainUtils do projektu

B) wygenerowany Łańcuch klucza CFUUID

 CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);
    udidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));

C) zapisał go do Key Chain Utils albo za każdym razem wygeneruje nowy Unikat

Kod Końcowy

+ (NSString *)GetDeviceID {
    NSString *udidString;
   udidString = [self objectForKey:@"deviceID"];
    if(!udidString)
    {
    CFUUIDRef cfuuid = CFUUIDCreate(kCFAllocatorDefault);
    udidString = (NSString*)CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, cfuuid));
    CFRelease(cfuuid);
        [self setObject:udidString forKey:@"deviceID"];
    }
    return udidString;
}

+(void) setObject:(NSString*) object forKey:(NSString*) key
{
    NSString *objectString = object;
    NSError *error = nil;
    [SFHFKeychainUtils storeUsername:key
                         andPassword:objectString
                      forServiceName:@"LIB"
                      updateExisting:YES
                               error:&error];

    if(error)
        NSLog(@"%@", [error localizedDescription]);
}

+(NSString*) objectForKey:(NSString*) key
{
    NSError *error = nil;
    NSString *object = [SFHFKeychainUtils getPasswordForUsername:key
                                                  andServiceName:@"LIB"
                                                           error:&error];
    if(error)
        NSLog(@"%@", [error localizedDescription]);

    return object;
}

Tutaj wpisz opis obrazka

Więcej informacji

 38
Author: Quamber Ali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-15 15:46:57

Niektórzy ludzie chcą dowiedzieć się więcej o różnych dostępnych opcjach, a jeśli tak, spójrz na odpowiedź od @NSQuamber.java. Jeśli chcesz wiedzieć, jak używać NSUUID i synchronizować się z iCloud, Czytaj dalej. Ten post skończył się bardziej długowieczny niż pierwotnie chciałem, ale mam nadzieję, że to jasne dla każdego, kto podejmuje te kroki!

Używanie NSUUID

Używam klasy NSUUID do tworzenia UUID:

NSUUID *uuid = [NSUUID UUID];

Następnie, aby utworzyć ciąg znaków, wystarczy wywołanie metody UUIDString:

NSString *uuidString = [uuid UUIDString];

Lub zrób to w jednej linijce:

NSString *uuidString = [[NSUUID UUID] UUIDString];

IMHO, jest to o wiele łatwiejsze niż próba użycia CFUUIDCreate i posiadania metody, którą musisz utrzymać.


EDIT: teraz używam UICKeyChainStore

Aby ustawić UUID za pomocą UICKeyChainStore:

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.sample.MyApp"];
keychain[@"com.sample.MyApp.user"] = userID;

Aby go odzyskać:

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.sample.MyApp"];
NSString *userID = keychain[@"com.sample.MyApp.user"];

Następnie zapisałem ten UUID do pęku kluczy za pomocą SSKeyChain

Aby ustawić UUID z SSKeyChain:

[SSKeychain setPassword:userID forService:@"com.sample.MyApp.user" account:@"com.sample.MyApp"];

Aby go odzyskać:

NSString *userID = [SSKeychain passwordForService:@"com.sample.MyApp.user" account:@"com.sample.MyApp"];

Po ustawieniu identyfikatora UUID na pęku kluczy, będzie on trwał, nawet jeśli użytkownik całkowicie odinstaluje aplikację, a następnie zainstaluje ją ponownie.

Synchronizacja z iCloud

Dlatego warto upewnić się, że wszystkie urządzenia użytkownika używają tego samego identyfikatora UUID. Ma to na celu zapewnienie, że dane są synchronizowane na wszystkich urządzeniach, a nie każde urządzenie myśli, że jest unikalnym użytkownikiem.

Było kilka pytań w komentarze do mojej odpowiedzi na temat tego, jak synchronizacja będzie działać, więc teraz, gdy mam to wszystko działa, podam więcej szczegółów.

[[58]}Konfigurowanie użycia iCloud/nsubiquitouskeyvaluestore
  1. Kliknij swój projekt u góry Nawigator projektu w Xcode.
  2. Wybierz Możliwości .
  3. włącz iCloud.

Powinien teraz wyglądać mniej więcej tak: Zrzut ekranu z iCloud włączony

Stosowanie NSUbiquitousKeyValueStore

Korzystanie z iCloud jest dość proste. Do napisania:

// create the UUID
NSUUID *userUUID = [[NSUUID UUID];
// convert to string
NSString *userID = [userUUID UUIDString];
// create the key to store the ID
NSString *userKey = @"com.sample.MyApp.user";

// Save to iCloud
[[NSUbiquitousKeyValueStore defaultStore] setString:userID forKey:userKey];

Do przeczytania:

// create the key to store the ID
NSString *userKey = @"com.sample.MyApp.user";

// read from iCloud
NSString *userID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey];

Zanim napiszesz nsubiquitouskeyvaluestore dokumentacja stwierdza, że musisz najpierw przeczytać z iCloud. Aby wymusić odczyt, wywołaj następującą metodę:

[[NSUbiquitousKeyValueStore defaultStore] synchronize];

Aby Twoja aplikacja otrzymywała powiadomienia o zmianach w iCloud, dodaj następujące powiadomienie:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(iCloudStoreDidChange:)
                                             name:NSUbiquitousKeyValueStoreDidChangeExternallyNotification
                                           object:[NSUbiquitousKeyValueStore defaultStore]];

Tworzenie UUID za pomocą iCloud

Łącząc NSUUID, SSKeychain i NSUbiquityKeyValueStore, oto mój metoda generowania ID użytkownika:

- (NSUUID *)createUserID {
    NSString *userKey = @"com.sample.MyApp.user";
    NSString *KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp";
    NSString *userID = [SSKeychain passwordForService:userKey account:KEYCHAIN_ACCOUNT_IDENTIFIER];
    if (userID) {
        return [[NSUUID UUID] initWithUUIDString:userID];
    }

    // check iCloud
    userID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey];
    if (!userID) {
        // none in iCloud, create one
        NSUUID *newUUID = [NSUUID UUID];
        userID = [newUUID UUIDString];
        // save to iCloud
        [[NSUbiquitousKeyValueStore defaultStore] setString:userID forKey:userKey];
    }

    // store the user ID locally
    [SSKeychain setPassword:userID forService:userKey account:KEYCHAIN_ACCOUNT_IDENTIFIER];
    return [[NSUUID UUID] initWithUUIDString:userID];
}
Jak upewnić się, że identyfikator użytkownika jest zsynchronizowany?]}

Ponieważ zapis do iCloud wymaga najpierw pobrania dowolnych danych w iCloud, umieściłem wywołanie synchronizacji na górze metody (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions. Dodałem tam również zgłoszenie rejestracji. To pozwala mi wykryć wszelkie zmiany z iCloud i odpowiednio je obsłużyć.

Oto próbka:

NSString *const USER_KEY = @"com.sample.MyApp.user";
NSString *const KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp";

- (void)iCloudStoreDidChange:(NSNotification *)notification {
    NSDictionary *userInfo = notification.userInfo;
    NSNumber *changeReason = userInfo[NSUbiquitousKeyValueStoreChangeReasonKey];
    NSArray *keysChanged = userInfo[NSUbiquitousKeyValueStoreChangedKeysKey];
    if (changeReason) {
        switch ([changeReason intValue]) {
            default:
            case NSUbiquitousKeyValueStoreServerChange:
            case NSUbiquitousKeyValueStoreInitialSyncChange:
                // check changed keys
                for (NSString *keyChanged in keysChanged) {
                    NSString *iCloudID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:keyChanged];
                    if (![keyChanged isEqualToString:USER_KEY]) {
                        NSLog(@"Unknown key changed [%@:%@]", keyChanged, iCloudID);
                        continue;
                    }

                    // get the local key
                    NSString *localID = [SSKeychain passwordForService:keyChanged account:KEYCHAIN_ACCOUNT_IDENTIFIER];
                    if (!iCloudID) {
                        // no value from iCloud
                        continue;
                    }
                    // local ID not created yet
                    if (!localID) {
                        // save the iCloud value locally
                        [SSKeychain setPassword:iCloudID forService:keyChanged account:KEYCHAIN_ACCOUNT_IDENTIFIER];
                        continue; // continue because there is no user information on the server, so no migration
                    }

                    if ([iCloudID isEqualToString:localID]) {
                        // IDs match, so continue
                        continue;
                    }

                    [self handleMigration:keyChanged from:localID to:iCloudID];
                }

                break;
            case NSUbiquitousKeyValueStoreAccountChange:
                // need to delete all data and download new data from server
                break;
        }
    }
}

Po uruchomieniu aplikacji lub po powrocie do na pierwszym planie wymuszam synchronizację z iCloud i weryfikuję integralność uuid.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self configureSecKeyWrapper];
    // synchronize data from iCloud first. If the User ID already exists, then we can initialize with it
    [[NSUbiquitousKeyValueStore defaultStore] synchronize];
    [self checkUseriCloudSync];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // synchronize changes from iCloud
    [[NSUbiquitousKeyValueStore defaultStore] synchronize];
    [self checkUseriCloudSync];
}

- (BOOL)checkUseriCloudSync {
    NSString *userKey = @"com.sample.MyApp.user";
    NSString *KEYCHAIN_ACCOUNT_IDENTIFIER = @"com.sample.MyApp";
    NSString *localID = [SSKeychain passwordForService:userKey account:KEYCHAIN_ACCOUNT_IDENTIFIER];
    NSString *iCloudID = [[NSUbiquitousKeyValueStore defaultStore] stringForKey:userKey];

    if (!iCloudID) {
        // iCloud does not have the key saved, so we write the key to iCloud
        [[NSUbiquitousKeyValueStore defaultStore] setString:localID forKey:userKey];
        return YES;
    }

    if (!localID || [iCloudID isEqualToString:localID]) {
        return YES;
    }

    // both IDs exist, so we keep the one from iCloud since the functionality requires synchronization
    // before setting, so that means that it was the earliest one
    [self handleMigration:userKey from:localID to:iCloudID];
    return NO;
}

Jeśli to, który UUID był pierwszy ma znaczenie

W moim przypadku użycia identyfikatora UserID założyłem, że wartość w iCloud jest tą, którą należy zachować, ponieważ będzie to pierwszy UUID wypchnięty do iCloud, niezależnie od tego, które urządzenie wygenerowało uuid jako pierwsze. Większość z was prawdopodobnie podążałaby tą samą ścieżką, ponieważ nie zależy wam na tym, do którego UUID się zdecyduje, o ile zdecyduje się na jeden. Dla tych z ci, którzy naprawdę dbają o to, który był pierwszy, proponuję przechowywać zarówno uuid, jak i generowanie znacznika czasu ([[NSDate date] timeIntervalSince1970]), abyś mógł sprawdzić, który jest starszy: {]}

// using dates
NSDate *uuid1Timestamp = [NSDate dateWithTimeIntervalSince1970:timestamp1];
NSDate *uuid2Timestamp = [NSDate dateWithTimeIntervalSince1970:timestamp2];
NSTimeInterval timeDifference = [uuid1 timeIntervalSinceDate:uuid2Timestamp];

// or just subtract
double timeDifference = timestamp1 - timestamp2;
 15
Author: mikeho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-20 20:12:31

Istnieje fajna alternatywa na Github, która generuje unikalny identyfikator na podstawie kombinacji adresu Mac i identyfikatora pakietu, który działa całkiem dobrze: UIDevice-with-UniqueIdentifier-for-iOS-5

 10
Author: Suhail Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-01 16:02:17

W iOS7 Apple wprowadziło właściwość tylko do odczytu o nazwie "identifierForVendor" w klasie UIDevice. Jeśli zdecydujesz się go użyć, należy zwrócić uwagę na następujące,

  • wartość ta może być zerowa, jeśli jest dostępna przed odblokowaniem urządzenia przez użytkownika
  • wartość zmienia się, gdy użytkownik usunie z urządzenia wszystkie aplikacje tego dostawcy, a następnie ponownie zainstaluje jedną lub więcej z nich.
  • wartość może się również zmienić podczas instalowania testowych kompilacji przy użyciu Xcode lub gdy instalacja aplikacji na urządzeniu przy użyciu dystrybucji ad-hoc.

Jeśli potrzebujesz identyfikatora do celów reklamowych, użyj właściwości advertisingIdentifier ASIdentifierManager. Należy jednak pamiętać, że punkt jeden omówiony powyżej jest nadal prawdziwy również w tym przypadku.

Źródło: https://developer.apple.com/library/ios/documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html#//apple_ref/occ/instp/UIDevice/identifierForVendor

 1
Author: ThE uSeFuL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-26 05:49:12

To naprawdę gorący temat. Mam aplikację, którą muszę przeprowadzić migrację, ponieważ używała UDID do nazwania pliku XML, który ma być przechowywany na serwerze. Następnie urządzenie z aplikacją połączy się z serwerem i pobierze jego określony udid.xml i parse go do pracy.

Myślałem, że rzeczywiście, jeśli użytkownik przeniesie się na nowe urządzenie, aplikacja pęknie. Więc naprawdę powinienem użyć czegoś innego. Chodzi o to, że nie używam bazy danych. Dane są po prostu przechowywane w formacie xml, jeden plik xml na urządzenie przechowywane w chmurze.

Im myślę, że najlepszą rzeczą byłoby, aby użytkownik wypełnił dane w Internecie, aby PHP utworzyło token w locie, który nie będzie przechowywany w bazie danych, ale raczej wysłany do użytkownika. Użytkownik może następnie wprowadzić token na urządzeniu docelowym i pobrać dany xml.

To byłoby moje rozwiązanie problemu. Nie wiem jednak, jak zaimplementować całe "tworzenie unikalnych tokenów".

 0
Author: marciokoko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-06 15:40:48