UIDevice uniqueIdentifier déconseillé - Que faire maintenant?

501

Il vient de voir que la propriété UIDevice uniqueIdentifier est obsolète dans iOS 5 et non disponible dans iOS 7 et supérieur. Aucune méthode ou propriété alternative ne semble être disponible ou à venir.

Beaucoup de nos applications existantes dépendent étroitement de cette propriété pour identifier de manière unique un appareil particulier. Comment pourrions-nous gérer ce problème à l'avenir?

La suggestion de la documentation en 2011-2012 était:

Considérations particulières

N'utilisez pas la propriété uniqueIdentifier. Pour créer un identifiant unique spécifique à votre application, vous pouvez appeler la CFUUIDCreatefonction pour créer un UUIDet l'écrire dans la base de données par défaut à l'aide de la NSUserDefaultsclasse.

Cependant, cette valeur ne sera pas la même si un utilisateur désinstalle et réinstalle l'application.

Oliver Pearmain
la source
1
Pour les applications utilisant toujours uniqueIdentifier, iOS7 renvoie désormais FFFFFFFF + identifierForVendor, qui brise un grand nombre d'applications d'abonnement non renouvelées mal écrites.
Rhythmic Fistman
Si par chance votre application utilise les notifications push, vous pouvez utiliser le jeton renvoyé par le service push d'Apple, il est également unique par appareil
Calin Chitu
@CalinChitu Si l'utilisateur n'accepte pas les notifications push, obtenez-vous toujours un pushID pour cet utilisateur?
Chase Roberts

Réponses:

272

Un UUID créé par CFUUIDCreate est unique si un utilisateur désinstalle et réinstalle l'application: vous en obtiendrez un nouveau à chaque fois.

Mais vous voudrez peut-être qu'elle ne soit pas unique, c'est-à-dire qu'elle devrait rester la même lorsque l'utilisateur désinstalle et réinstalle l'application. Cela nécessite un peu d'effort, car l'identifiant par périphérique le plus fiable semble être l'adresse MAC. Vous pouvez interroger le MAC et l'utiliser comme UUID.

Edit: Il faut toujours interroger le MAC de la même interface, bien sûr. Je suppose que le meilleur pari est avec en0. Le MAC est toujours présent, même si l'interface n'a pas d'IP / est en panne.

Edit 2: Comme cela a été souligné par d'autres, la solution préférée depuis iOS 6 est - [UIDevice identifierForVendor] . Dans la plupart des cas, vous devriez pouvoir l'utiliser en remplacement de l'ancien -[UIDevice uniqueIdentifier](mais un UUID qui est créé lorsque l'application démarre pour la première fois est ce qu'Apple semble vouloir que vous utilisiez).

Edit 3: Donc, ce point majeur ne se perd pas dans le bruit des commentaires: n'utilisez pas le MAC comme UUID, créez un hachage en utilisant le MAC . Ce hachage créera toujours le même résultat à chaque fois, même sur les réinstallations et les applications (si le hachage est effectué de la même manière). Quoi qu'il en soit, de nos jours (2013), cela n'est plus nécessaire, sauf si vous avez besoin d'un identifiant d'appareil "stable" sur iOS <6.0.

Edit 4: dans iOS 7, Apple retourne désormais toujours une valeur fixe lors de l'interrogation du MAC pour contrecarrer spécifiquement le MAC comme base pour un schéma d' ID . Donc, vous devriez maintenant vraiment utiliser - [UIDevice identifierForVendor] ou créer un UUID par installation.

DarkDust
la source
8
L'adresse mac ne change-t-elle pas selon que l'utilisateur est connecté via Wifi ou non?
Oliver Pearmain
1
@DarkDust: mais comme l'interface active change lorsque vous passez du wifi au modem cellulaire, l'adresse MAC de l'interface active devrait également changer; à moins que vous ne choisissiez toujours une interface particulière pour obtenir le MAC
user102008
3
@Roger Nolan: Veuillez ne pas modifier les réponses des autres et ajouter des éléments qui semblent provenir de l'auteur d'origine. Merci.
DarkDust
2
@RogerNolan Tant que la publication n'est pas une réponse de la communauté, les modifications visent à corriger des erreurs et de telles choses, pas à ajouter de nouvelles choses. Il y a une raison pour laquelle vous avez obtenu le privilège. Imaginez que je modifie votre réponse et que j'écris des BS, les gens penseraient que vous auriez écrit cela. Je doute que cela vous plaise :-) Mais vous n'êtes pas averti qu'un montage s'est produit, je ne l'ai découvert que par accident.
DarkDust le
3
Apple rejette désormais les applications qui utilisent MAC hachée.
Idan
91

Vous pouvez déjà utiliser votre alternative pour Apple UDID. Kind guy gekitz a écrit une catégorie sur UIDevicelaquelle va générer une sorte d' UDIDadresse basée sur l'adresse mac et l'identifiant du bundle.

Vous pouvez trouver le code sur github

Serhii Mamontov
la source
3
Cette implémentation est unique (adresse MAC) pour un appareil à travers les réinstallations, comme uniqueId d'Apple, mais respecte également la confidentialité, étant également unique pour une application (utilisez également bundleId) ... Un must have à mon humble avis, qu'Apple devrait inclure dans ses API. .. au lieu de déprécier sans aucune alternative.
Vincent Guerci
8
Bien qu'il utilise l'ancienne licence bsd avec la clause publicitaire, beurk.
jbtule
8
Pour quiconque trouve maintenant ce post, la licence a été modifiée depuis le commentaire ci-dessus par jbtule.
James
1
Comme indiqué dans ce commentaire de validation, la bibliothèque en l'état pose un grave problème de fuite de confidentialité et ne doit pas être utilisée:
Will
15
À partir d'iOS 7, le système renvoie toujours la valeur 02:00:00:00:00:00lorsque vous demandez l'adresse MAC sur n'importe quel appareil. Vérifiez ici: developer.apple.com/library/prerelease/ios/releasenotes/General/…
Hejazi
61

Sur la base du lien proposé par @moonlight, j'ai fait plusieurs tests et cela semble être la meilleure solution. Comme le dit @DarkDust, la méthode vérifie en0laquelle est toujours disponible.
Il y a 2 options:
uniqueDeviceIdentifier(MD5 de MAC + CFBundleIdentifier)
et uniqueGlobalDeviceIdentifier(MD5 de MAC), elles retournent toujours les mêmes valeurs.
Ci-dessous les tests que j'ai effectués (avec le vrai appareil):

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

XXXX21f1f19edff198e2a2356bf4XXXX - (Wi-Fi) après avoir supprimé et réinstallé l'application XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) après avoir supprimé et installé l'application

J'espère que c'est utile.

EDIT:
Comme d'autres l'ont souligné, cette solution dans iOS 7 n'est plus utile car elle uniqueIdentifiern'est plus disponible et la requête d'adresse MAC renvoie désormais toujours 02: 00: 00: 00: 00: 00

Tapis
la source
13
cela ne fonctionnera pas sur iOS7, Apple élimine l'utilisation de l'adresse MAC.
Sarim Sidd
@SarimSidd Pour l'instant les informations sur iOS 7 sont sous NDA, nous ne pouvons pas en discuter ici.
Mat
57

regarde ça,

nous pouvons utiliser le trousseau au lieu de la NSUserDefaultsclasse, pour stocker UUIDcréé par CFUUIDCreate.

de cette façon, nous pourrions éviter pour les UUIDloisirs avec la réinstallation, et obtenir toujours la même chose UUIDpour la même application, même l'utilisateur désinstaller et réinstaller.

UUID sera recréé au moment de la réinitialisation de l'appareil par l'utilisateur.

J'ai essayé cette méthode avec SFHFKeychainUtils et cela fonctionne comme un charme.

ytur
la source
33
Cette méthode remplace solidement l'UDID. Il présente également l'avantage supplémentaire de recréer l'identifiant lors du format de l'appareil (par exemple, si l'appareil change de propriétaire). Cependant, il est important de noter que le trousseau peut être restauré sur d'autres appareils si l'utilisateur crypte sa sauvegarde. Cela peut entraîner une situation où plusieurs appareils partagent le même UUID. Pour éviter cela, définissez l'accessibilité de votre élément de trousseau sur kSecAttrAccessibleAlwaysThisDeviceOnly. Cela garantira que votre UUID ne migre pas vers un autre appareil. Pour accéder à votre UUID à partir d'autres applications, utilisez la kSecAttrAccessGroupclé.
Jeevan Takhar
Où exactement (quelle clé) êtes-vous censé utiliser pour stocker l'UUID dans le trousseau?
lostintranslation
Opps! lien cassé
COVID19
48

Créez votre propre UUID, puis stockez-le dans le trousseau. Ainsi, il persiste même lorsque votre application est désinstallée. Dans de nombreux cas, il persiste également même si l'utilisateur migre entre les appareils (par exemple, sauvegarde complète et restauration vers un autre appareil).

En fait, cela devient un identifiant utilisateur unique en ce qui vous concerne. (encore mieux que l' identifiant de l' appareil ).

Exemple:

Je définis une méthode personnalisée pour créer un en UUIDtant que:

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

Vous pouvez ensuite le stocker lors KEYCHAINdu tout premier lancement de votre application. Pour qu'après le premier lancement, nous puissions simplement l'utiliser à partir du trousseau, pas besoin de le régénérer. La principale raison d'utiliser le trousseau pour stocker est la suivante: lorsque vous définissez le UUIDsur le trousseau, il persistera même si l'utilisateur désinstalle complètement l'application, puis l'installe à nouveau. . C'est donc le moyen permanent de le stocker, ce qui signifie que la clé sera unique tout le long.

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

Au lancement de l'application, incluez le code suivant:

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

Téléchargez le fichier SSKeychain.m et .h à partir de sskeychain et faites glisser le fichier SSKeychain.m et .h vers votre projet et ajoutez "Security.framework" à votre projet. Pour utiliser UUID par la suite, utilisez simplement:

NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];
Samir Jwarchan
la source
Parce qu'un identifiant ForVendor fonctionne n'est pas parfaitement. Dans certains cas, peut retourner un nil ou 0x0. Cette méthode semble fonctionner parfaitement
CReaTuS
3
Quelqu'un a-t-il validé que cela fonctionne sur iOS7 après le cycle de désinstallation / réinstallation + soumission de l'application Apple vérifiée?
mindbomb
J'ai commencé à utiliser cette solution. Plusieurs tests sur 2 appareils (reconstruire, réinstaller, éteindre l'appareil) m'ont montré que l'identifiant est le même. iOS 10.3.
deko
16

Vous pouvez peut-être utiliser:

[UIDevice currentDevice].identifierForVendor.UUIDString

La documentation d'Apple décrit identifierForVender comme suit:

La valeur de cette propriété est la même pour les applications provenant du même fournisseur et exécutées sur le même appareil. Une valeur différente est renvoyée pour les applications sur le même appareil provenant de différents fournisseurs et pour les applications sur différents appareils, quel que soit le fournisseur.

diadyne
la source
Curieux de savoir pourquoi personne n'a soulevé cette question jusqu'à récemment ... Et maintenant je vois que c'est nouveau avec iOS 6.
James Boutcher
1
Si l'utilisateur met à jour ios et / ou installe un nouvel ios, la valeur de identifierForVendor changera ou restera la même?
Sunil Zalavadiya
1
Après avoir supprimé toutes les applications du même fournisseur, cette valeur sera modifiée.
Mitesh Khatri
14

Vous voudrez peut-être envisager d'utiliser OpenUDIDce qui est un remplacement sans rendez-vous pour les obsolètes UDID.

Fondamentalement, pour correspondre à UDID, les fonctionnalités suivantes sont requises:

  1. unique ou suffisamment unique (une collision à faible probabilité est probablement très acceptable)
  2. persistance à travers les redémarrages, les restaurations, les désinstallations
  3. disponible sur les applications de différents fournisseurs (utile pour acquérir des utilisateurs via les réseaux CPI) -

OpenUDID remplit ce qui précède et a même un mécanisme de retrait intégré pour un examen ultérieur.

Vérifiez http://OpenUDID.org qu'il pointe vers le GitHub correspondant. J'espère que cela t'aides!

En guise de remarque, je voudrais éviter toute alternative d'adresse MAC. Alors que l'adresse MAC apparaît comme une solution tentante et universelle, assurez-vous que ce fruit bas est empoisonné. L'adresse MAC est très sensible, et Apple peut très bien déprécier l'accès à celle-ci avant que vous ne puissiez même dire "SOUMETTRE CETTE APP" ... l'adresse réseau MAC est utilisée pour authentifier certains appareils sur des réseaux privés (WLAN) ou d'autres réseaux privés virtuels réseaux (VPN). .. il est encore plus sensible que l'ancien UDID!

ylechelle
la source
Je suis vraiment curieux de savoir comment cela fonctionne? Le code est écrit en Objective-C, mais il n'y a pas d'autre bonne solution qui réponde aux exigences ci-dessus, alors qu'est-ce qui rend ce cadre différent? La solution que ce framework utilise devrait également être possible de poster comme réponse suggérée ici ...
jake_hetfield
Je suis d'accord - l'adresse MAC peut également être configurée manuellement ("clonée"), bien qu'elle ne soit pas probable pour la plupart. Je dois protester contre le D dans UDID. Ce n'est pas un ID de périphérique, c'est un UUID (Universally Unique Identifier). L'ID de l'appareil est estampillé par Apple de l'usine sur chaque appareil de la ROM.
Jay Imerman
La meilleure solution pour iOS7 fait également ce qui est réellement nécessaire pour identifier un appareil de manière unique
Vishal Dharankar
1
OpenUDID est obsolète et n'est pas recommandé à utiliser
mkll
11

Je suis sûr qu'Apple a agacé beaucoup de gens avec ce changement. Je développe une application de comptabilité pour iOS et j'ai un service en ligne pour synchroniser les modifications apportées sur différents appareils. Le service gère une base de données de tous les appareils et des modifications qui doivent leur être propagées. Il est donc important de savoir quels appareils sont lesquels. Je garde la trace des appareils utilisant l'UIDevice uniqueIdentifier et pour ce qu'il vaut, voici mes réflexions.

  • Générer un UUID et stocker dans les valeurs par défaut des utilisateurs? Pas bon car cela ne persiste pas lorsque l'utilisateur supprime l'application. S'ils réinstallent plus tard, le service en ligne ne doit pas créer un nouvel enregistrement de périphérique, ce qui gaspillerait des ressources sur le serveur et donnerait une liste de périphériques contenant le même deux fois ou plus. Les utilisateurs verraient plus d'un "iPhone de Bob" répertoriés s'ils réinstallaient l'application.

  • Générer un UUID et le stocker dans le trousseau? C'était mon plan, car il persiste même lorsque l'application est désinstallée. Mais lors de la restauration d'une sauvegarde iTunes sur un nouvel appareil iOS, le trousseau est transféré si la sauvegarde est cryptée. Cela pourrait conduire à deux appareils contenant le même ID d'appareil si les anciens et les nouveaux appareils sont tous deux en service. Ceux-ci doivent être répertoriés comme deux appareils dans le service en ligne, même si le nom de l'appareil est le même.

  • Générer un hachage l'adresse MAC et l'ID de bundle? Cela ressemble à la meilleure solution pour ce dont j'ai besoin. En hachant avec l'ID de l'ensemble, l'ID d'appareil généré ne permettra pas de suivre l'appareil sur les applications et j'obtiens un ID unique pour la combinaison app + appareil.

Il est intéressant de noter que la propre documentation d'Apple fait référence à la validation des reçus du Mac App Store en calculant un hachage de l'adresse MAC du système plus l'ID et la version du bundle. Donc, cela semble permis par la politique, que cela passe par l'examen des applications, je ne sais pas encore.

Mathew Waters
la source
10
Pour éviter la situation décrite dans votre deuxième point, définissez l'accessibilité de votre élément de trousseau sur kSecAttrAccessibleAlwaysThisDeviceOnly. Cela garantira que votre UUID ne sera pas restauré sur d'autres appareils, même si la sauvegarde est cryptée.
Jeevan Takhar
C'est en effet le comportement que j'ai vu à plusieurs reprises. Par exemple, j'enregistre mon iPhone pour Google Sync. Ensuite, j'ai obtenu un nouvel iPhone, enregistrez-le et le tour est joué - j'ai maintenant 2 iPhones répertoriés dans mes paramètres de synchronisation.
Jay Imerman
11

Il ressemble à iOS 6, Apple vous recommande d'utiliser la classe NSUUID .

Du message maintenant dans les documents UIDevice pour la uniqueIdentifierpropriété:

Déconseillé dans iOS 5.0. Utilisez à la place la propriété identifierForVendor de cette classe ou la propriété advertisingIdentifier de la classe ASIdentifierManager, ou utilisez la méthode UUID de la classe NSUUID pour créer un UUID et l'écrire dans la base de données par défaut de l'utilisateur.

Nate
la source
10

Peut aider: utilisez le code ci-dessous, il sera toujours unique sauf que vous effacez (formatez) votre appareil.

UIDevice *myDevice=[UIDevice currentDevice];
NSString *UUID = [[myDevice identifierForVendor] UUIDString];
Ashvin Ajadiya
la source
1
J'ai utilisé ce code. Mais quand j'ai supprimé l'application et que j'ai à nouveau installé, j'ai eu un nouvel ID
Durgaprasad
1
c'est une solution simple si vous n'avez pas besoin d'une méthode robuste. je l'utilise dans mon application maintenant.
Reuben L.
@Durgaprasad: il changera toujours parce qu'il dépend du fournisseur. Par exemple: 1. Si vous avez installé une application avec bundleidenedifier: com.abcd.com => alors cela changera. 2. Si vous avez installé deux applications avec bundleidenedifier: com.abcd.com => Alors il ne chnage pas (Gardez une seule application pendant)
Ashvin Ajadiya
7

Je voudrais aussi vous suggérons de changer au- dessus de uniqueIdentifierla cette bibliothèque open source (2 catégories simples vraiment) qui utilisent l'adresse MAC de l'appareil avec le Bundle App Identifier pour générer un identifiant unique dans vos applications qui peuvent être utilisées en remplacement UDID.

Gardez à l'esprit que contrairement à l'UDID, ce nombre sera différent pour chaque application.

Vous avez simplement besoin d'importer les inclus NSStringet les UIDevicecatégories et appel [[UIDevice currentDevice] uniqueDeviceIdentifier]comme ceci:

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

Vous pouvez le trouver sur Github ici:

UIDevice avec UniqueIdentifier pour iOS 5


Voici les catégories (juste les fichiers .m - vérifiez le projet github pour les en-têtes):

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
chown
la source
3
À partir d'iOS 7, Apple renverra une valeur constante pour l'adresse MAC. C'est parfaitement logique. L'adresse MAC est sensible.
Roberto
4

L'adresse MAC peut être usurpée, ce qui rend une telle approche inutile pour lier du contenu à des utilisateurs spécifiques ou pour implémenter des fonctionnalités de sécurité telles que des listes noires.

Après quelques recherches supplémentaires, il me semble que nous nous retrouvons sans alternative appropriée à partir de maintenant. J'espère sérieusement qu'Apple reconsidérera sa décision.

Ce serait peut-être une bonne idée d'envoyer un e-mail à Apple à ce sujet et / ou de déposer une demande de bug / fonctionnalité à ce sujet, car ils ne sont peut-être même pas conscients des conséquences complètes pour les développeurs.

Toastor
la source
13
Un point valable, mais je pense que l'UUID peut également être usurpé / transféré sur un téléphone jailbreaké, donc techniquement [l'UIDevice uniqueIdentifier] existant est tout aussi imparfait.
Oliver Pearmain
3
Vous pouvez toujours créer un identifiant sur le serveur et l'enregistrer sur l'appareil. C'est ainsi que la plupart des applications le font. Je ne comprends pas pourquoi les programmeurs iOS ont besoin de quelque chose de spécial.
Sulthan
1
@Sulthan ne fonctionne pas sur iOS car si vous désinstallez une application, toutes ses données disparaissent, il n'y a donc aucun moyen de garantir un identifiant d'appareil unique de cette façon.
lkraider
4
Pas si vous l'enregistrez dans le trousseau. Quoi qu'il en soit, je n'ai jamais vu d'application où c'était un problème. Si l'application et les données ont été supprimées, vous n'avez pas besoin du même identifiant d'appareil. Si vous souhaitez identifier l'utilisateur, demandez-lui un e-mail.
Sulthan
L'accès à l'adresse MAC a également été interdit par Apple dans la nouvelle version d'iOS;
Ans
4

UIDevice identifierForVendor introduit dans iOS 6 fonctionnerait pour vos besoins.

identifierForVendorest une chaîne alphanumérique qui identifie de manière unique un appareil auprès du fournisseur de l'application. (lecture seulement)

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

La valeur de cette propriété est la même pour les applications provenant du même fournisseur et exécutées sur le même appareil. Une valeur différente est renvoyée pour les applications sur le même appareil qui proviennent de différents fournisseurs, et pour les applications sur différents appareils, selon le fournisseur.

Disponible dans iOS 6.0 et versions ultérieures et déclaré dans UIDevice.h

Pour iOS 5, reportez-vous à ce lien UIDevice-with-UniqueIdentifier-for-iOS-5

Mahendra Liya
la source
4

Utilisation du SSKeychain et du code mentionnés ci-dessus. Voici le code à copier / coller (ajoutez le module 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;

}

Komposr
la source
3

Le code suivant aide à obtenir l'UDID:

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

Voici le code que j'utilise pour obtenir l'ID pour iOS 5 et 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];
}
Grzegorz Krukowski
la source
Que faites-vous à propos de l'avertissement du compilateur PerformSelector may cause a leak because its selector is unknown?
Basil Bourque
Vous ne pouvez plus utiliser advertisingIdentifier à cet effet car Apple le rejettera. Plus d'infos: techcrunch.com/2014/02/03/…
codeplasma
2

iOS 11 a introduit le framework DeviceCheck. Il a une solution complète pour identifier de manière unique l'appareil.

Santosh Botre
la source
1

Une façon pratique d'obtenir l'UDID:

  1. Lancez un serveur Web dans l'application avec deux pages: l'une doit renvoyer un profil MobileConfiguration spécialement conçu et l'autre doit collecter l'UDID. Plus d'infos ici , ici et ici .
  2. Vous ouvrez la première page dans Mobile Safari depuis l'intérieur de l'application et il vous redirige vers Settings.app en demandant d'installer le profil de configuration. Après avoir installé le profil, l'UDID est envoyé à la deuxième page Web et vous pouvez y accéder depuis l'intérieur de l'application. (Settings.app possède tous les droits nécessaires et différentes règles de sandbox).

Un exemple utilisant 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)
    }
}

Voici le contenu de 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'installation du profil échouera (je n'ai pas pris la peine d'implémenter une réponse attendue, voir la documentation ), mais l'application obtiendra un UDID correct. Et vous devez également signer le mobileconfig .

bzz
la source
1

Pour Swift 3.0, veuillez utiliser le code ci-dessous.

let deviceIdentifier: String = (UIDevice.current.identifierForVendor?.uuidString)!
NSLog("output is : %@", deviceIdentifier)
Ganesh
la source
1
iOS 11 a introduit le framework DeviceCheck. Il a une solution complète pour identifier de manière unique l'appareil.
Santosh Botre
1

Vous pouvez utiliser

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

Ce qui est unique pour l'appareil dans toutes les applications.

Dhaval
la source
0

Si quelqu'un tombe sur cette question, lors de la recherche d'une alternative. J'ai suivi cette approche en IDManagerclasse, c'est une collection de différentes solutions. KeyChainUtil est un wrapper pour lire à partir du trousseau. Vous pouvez également utiliser le hashed MAC addresscomme une sorte d'ID unique.

/*  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;
}
karim
la source
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;
}
chowdary mahesh
la source
0

Nous pouvons utiliser identifierForVendor pour 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;
}

--Note importante ---

UDID et identifierForVendor sont différents: ---

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.
HDdeveloper
la source
êtes-vous sûr ? pouvons-nous utiliser identifierForVendor pour ios7 ,?
Avis
0

Apple a masqué l'UDID de toutes les API publiques, à commencer par iOS 7. Tout UDID commençant par FFFF est un faux ID. Les applications "Envoyer UDID" qui fonctionnaient auparavant ne peuvent plus être utilisées pour collecter l'UDID pour les appareils de test. (soupir!)

L'UDID s'affiche lorsqu'un appareil est connecté à XCode (dans l'organiseur) et lorsque l'appareil est connecté à iTunes (bien que vous deviez cliquer sur `` Numéro de série '' pour que l'identifiant s'affiche.

Si vous devez obtenir l'UDID d'un appareil à ajouter à un profil d'approvisionnement, et que vous ne pouvez pas le faire vous-même dans XCode, vous devrez les suivre à travers les étapes pour le copier / coller à partir d'iTunes.

Existe-t-il un moyen depuis (sortie d'iOS 7) d'obtenir l'UDID sans utiliser iTunes sur un PC / Mac?

Preet
la source
0

J'avais aussi un problème et la solution est simple:

    // 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;
Ahmet Kazim Günay
la source
0

Une alternative non parfaite mais l'une des meilleures et des plus proches de l'UDID (dans Swift utilisant iOS 8.1 et Xcode 6.1):

Génération d'un UUID aléatoire

let strUUID: String = NSUUID().UUIDString

Et utilisez la bibliothèque KeychainWrapper :

Ajoutez une valeur de chaîne au trousseau:

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

Récupérez une valeur de chaîne à partir du trousseau:

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

Supprimez une valeur de chaîne du trousseau:

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

Cette solution utilise le trousseau, donc l'enregistrement stocké dans le trousseau sera conservé, même après la désinstallation et la réinstallation de l'application. La seule façon de supprimer cet enregistrement est de réinitialiser tous les contenus et paramètres de l'appareil. C'est pourquoi j'ai mentionné que cette solution de substitution n'est pas parfaite mais reste l'une des meilleures solutions de remplacement pour UDID sur iOS 8.1 à l'aide de Swift.

Roi-sorcier
la source
0

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

Garçon Ankit
la source