UIDevice uniqueIdentifier descontinuado - O que fazer agora?

501

Acabou de constatar que a propriedade UIDevice uniqueIdentifier está obsoleta no iOS 5 e indisponível no iOS 7 e superior. Nenhum método ou propriedade alternativa parece estar disponível ou disponível.

Muitos de nossos aplicativos existentes dependem fortemente dessa propriedade para identificar exclusivamente um dispositivo específico. Como podemos lidar com esse problema daqui para frente?

A sugestão da documentação em 2011-2012 foi:

Considerações Especiais

Não use a propriedade uniqueIdentifier. Para criar um identificador exclusivo específico para seu aplicativo, você pode chamar a CFUUIDCreatefunção para criar um UUIDe gravá-lo no banco de dados de padrões usando a NSUserDefaultsclasse

No entanto, esse valor não será o mesmo se um usuário desinstalar e reinstalar o aplicativo.

Oliver Pearmain
fonte
1
Para aplicativos que ainda usam o uniqueIdentifier, o iOS7 agora retorna FFFFFFFF + identifierForVendor, que está quebrando muitos aplicativos de assinatura não renováveis ​​mal gravados.
Rhythmic Fistman
Se por sorte seus usos de aplicativos notificações Push, você pode usar a parte traseira enviado token do serviço de push da Apple, ele é único por dispositivo bem
Calin Chitu
@CalinChitu Se o usuário não aceitar notificações por push, você ainda recebe um pushID para esse usuário?
Chase Roberts

Respostas:

272

Um UUID criado por CFUUIDCreate é único se um usuário desinstalar e reinstalar o aplicativo: você receberá um novo a cada vez.

Mas você pode querer que ele não seja exclusivo, ou seja, deve permanecer o mesmo quando o usuário desinstalar e reinstalar o aplicativo. Isso requer um pouco de esforço, pois o identificador por dispositivo mais confiável parece ser o endereço MAC. Você pode consultar o MAC e usá-lo como UUID.

Editar: é preciso sempre consultar o MAC da mesma interface, é claro. Eu acho que a melhor aposta é com en0. O MAC está sempre presente, mesmo que a interface não tenha IP / esteja inoperante.

Edit 2: Como foi apontado por outros, a solução preferida desde o iOS 6 é - [UIDevice identifierForVendor] . Na maioria dos casos, você deve usá-lo como um substituto para o antigo -[UIDevice uniqueIdentifier](mas um UUID criado quando o aplicativo é iniciado pela primeira vez é o que a Apple quer que você use).

Edit 3: Portanto, este ponto importante não se perde no ruído do comentário: não use o MAC como UUID, crie um hash usando o MAC . Esse hash sempre criará o mesmo resultado sempre, mesmo em reinstalações e aplicativos (se o hash for feito da mesma maneira). De qualquer forma, atualmente (2013) isso não é mais necessário, exceto se você precisar de um identificador de dispositivo "estável" no iOS <6.0.

Edição 4: no iOS 7, a Apple agora sempre retorna um valor fixo ao consultar o MAC para impedir especificamente o MAC como base para um esquema de ID . Então agora você realmente deve usar - [UIDevice identifierForVendor] ou criar um UUID por instalação.

DarkDust
fonte
8
O endereço mac não muda dependendo se o usuário está conectado via Wifi ou não?
Oliver Pearmain
1
@DDarkDust: mas como a interface ativa muda quando você alterna do modem wifi para o celular, o endereço MAC da interface ativa também deve mudar; a menos que você sempre escolher um determinado interface para obter o MAC
user102008
3
@ Roger Nolan: Por favor, não edite as respostas de outras pessoas e adicione coisas que pareçam ter saído do autor original. Obrigado.
DarkDust 27/03
2
@RogerNolan Desde que a postagem não seja uma resposta da comunidade, as edições são para corrigir erros e coisas assim, não para adicionar coisas novas. Há uma razão para você ganhar o privilégio. Imagine que eu edite sua resposta e escreva algumas BS, as pessoas pensariam que você teria escrito isso. Duvido que você goste disso :-) Mas você não é notificado de que uma edição aconteceu, eu só descobri por acidente.
DarkDust 8/04
3
A Apple agora rejeita aplicativos que usam MAC com hash.
Idan
91

Você já pode usar sua alternativa para a Apple UDID. O tipo gekitz escreveu uma categoria na UIDevicequal irá gerar algum tipo de UDIDbaseado no endereço mac do dispositivo e no identificador de pacote.

Você pode encontrar código no github

Serhii Mamontov
fonte
3
Essa implementação é exclusiva (endereço MAC) para um dispositivo em reinstalações, como o uniqueId da Apple, mas também respeita a privacidade, sendo também exclusiva para um aplicativo (também usa o bundleId) ... É necessário ter um imho, que a Apple deve incluir em suas APIs. .. em vez de descontinuar sem alternativas.
Vincent Guerci
8
Embora ele use a licença bsd de estilo antigo com a cláusula de publicidade, eca.
Jbtule
8
Para qualquer outra pessoa que está encontrando este post, a licença foi alterada desde o comentário acima por jbtule.
James
1
Conforme discutido neste comentário de confirmação, a biblioteca como está apresenta um sério problema de vazamento de privacidade e não deve ser usada:
Será
15
A partir do iOS 7, o sistema sempre retorna o valor 02:00:00:00:00:00quando você solicita o endereço MAC em qualquer dispositivo. Verifique aqui: developer.apple.com/library/prerelease/ios/releasenotes/General/…
Hejazi
61

Com base no link proposto pelo @moonlight, fiz vários testes e parece ser a melhor solução. Como o @DarkDust diz, o método verifica se en0está sempre disponível.
Existem 2 opções:
uniqueDeviceIdentifier(MD5 do MAC + CFBundleIdentifier)
e uniqueGlobalDeviceIdentifier(MD5 do MAC), sempre retornam os mesmos valores.
Abaixo dos testes que fiz (com o dispositivo real):

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

XXXX21f1f19edff198e2a2356bf4XXXX - (Wi-Fi) após remover e reinstalar o aplicativo XXXX7dc3c577446a2bcbd77935bdXXXX (Wi-Fi) após remover e instalar o aplicativo

Espero que seja útil.

EDIT:
Como outros salientaram, esta solução no iOS 7 não é mais útil, pois uniqueIdentifiernão está mais disponível e a consulta de endereços MAC agora sempre retorna 02: 00: 00: 00: 00: 00

Esteira
fonte
13
isso não funcionará no iOS7, a Apple elimina o uso do endereço MAC.
Sarim Sidd
@SarimSidd Por enquanto, as informações sobre o iOS 7 estão sob NDA, não podemos discutir aqui.
Mat
57

Veja isso,

podemos usar Keychain em vez de NSUserDefaultsclasse, para armazenar UUIDcriado por CFUUIDCreate.

dessa maneira, poderíamos evitar a UUIDrecreação com a reinstalação e obter sempre o mesmo UUIDpara o mesmo aplicativo, mesmo o usuário desinstala e reinstala novamente.

UUID será recriado apenas quando o dispositivo for redefinido pelo usuário.

Eu tentei esse método com SFHFKeychainUtils e funciona como um encanto.

ytur
fonte
33
Este método é um substituto sólido para o UDID. Ele também tem o benefício adicional de recriar o identificador no formato do dispositivo (por exemplo, se o dispositivo mudar de proprietário). No entanto, é importante observar que o chaveiro pode ser restaurado para outros dispositivos se o usuário criptografar o backup. Isso pode resultar em uma situação em que vários dispositivos compartilham o mesmo UUID. Para evitar isso, defina a acessibilidade do seu item de chaveiro como kSecAttrAccessibleAlwaysThisDeviceOnly. Isso garantirá que o seu UUID não seja migrado para nenhum outro dispositivo. Para acessar seu UUID a partir de outros aplicativos, utilize a kSecAttrAccessGrouptecla
21412 Jeevan Takhar
Onde exatamente (qual chave) você deve usar para armazenar o UUID no chaveiro?
Lostintranslation
Opps! link está quebrado
COVID19 08/04
48

Crie seu próprio UUID e armazene-o no chaveiro. Portanto, ele persiste mesmo quando seu aplicativo é desinstalado. Em muitos casos, ele também persiste mesmo que o usuário migre entre dispositivos (por exemplo, backup completo e restauração para outro dispositivo).

Efetivamente, ele se torna um identificador de usuário exclusivo para você. (ainda melhor que o identificador de dispositivo ).

Exemplo:

Estou definindo um método personalizado para criar um UUIDas:

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

Você pode armazená-lo logo no KEYCHAINprimeiro lançamento do seu aplicativo. Para que, após o primeiro lançamento, possamos simplesmente usá-lo no chaveiro, sem necessidade de regenerá-lo. O principal motivo para usar o Keychain para armazenar é: Quando você define o UUIDKeychain, ele persiste mesmo que o usuário desinstale completamente o aplicativo e o instale novamente. . Portanto, essa é a maneira permanente de armazená-la, o que significa que a chave será única o tempo todo.

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

No lançamento do aplicativo, inclua o seguinte código:

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

Faça o download do arquivo SSKeychain.m e .h do sskeychain e arraste o arquivo SSKeychain.m e .h para o seu projeto e adicione "Security.framework" ao seu projeto. Para usar o UUID depois, basta usar:

NSString *retrieveuuid = [SSKeychain passwordForService:@"your app identifier" account:@"user"];
Samir Jwarchan
fonte
Como um identifierForVendor está funcionando, não é perfeito. Em alguns casos, pode retornar um zero ou 0x0. Parece que este método está funcionando perfeitamente
CReaTuS
3
alguém validado está trabalhando no iOS7 após o ciclo de desinstalação / reinstalação + envio verificado do aplicativo da apple?
mindbomb
Comecei a usar esta solução. Vários testes em 2 dispositivos (reconstruir, reinstalar, desligar o dispositivo) me mostraram que o ID é o mesmo. iOS 10.3.
deko
16

Talvez você possa usar:

[UIDevice currentDevice].identifierForVendor.UUIDString

A documentação da Apple descreve identifierFor coleta da seguinte maneira:

O valor dessa propriedade é o mesmo para aplicativos provenientes do mesmo fornecedor em execução no mesmo dispositivo. Um valor diferente é retornado para aplicativos no mesmo dispositivo provenientes de diferentes fornecedores e para aplicativos em dispositivos diferentes, independentemente do fornecedor.

diadyne
fonte
Curioso porque ninguém trouxe este até recentemente ... E agora eu vejo que há de novo no iOS 6.
James Boutcher
1
Se o usuário atualizar o ios e / ou instalar novos ios, o valor de identifierForVendor será alterado ou permanecerá o mesmo?
Sunil Zalavadiya
1
Depois de remover todos os aplicativos do mesmo fornecedor, esse valor será alterado.
Mitesh Khatri
14

Você pode considerar o uso de OpenUDIDum substituto para os obsoletos UDID.

Basicamente, para corresponder a UDID, os seguintes recursos são necessários:

  1. único ou suficientemente único (uma colisão de baixa probabilidade é provavelmente muito aceitável)
  2. persistência em reinicializações, restaurações, desinstalações
  3. disponível em aplicativos de diferentes fornecedores (útil para adquirir usuários através de redes CPI) -

OpenUDID cumpre o disposto acima e ainda possui um mecanismo de desativação interno para consideração posterior.

Verifique http://OpenUDID.org e aponte para o GitHub correspondente. Espero que isto ajude!

Como uma observação lateral, eu evitaria qualquer alternativa de endereço MAC. Embora o endereço MAC pareça uma solução tentadora e universal, certifique-se de que esta fruta baixa seja envenenada. O endereço MAC é muito sensível, e a Apple pode muito bem descontinuar o acesso a esse antes mesmo que você possa dizer "ENVIAR ESTE APP" ... o endereço de rede MAC é usado para autenticar determinados dispositivos em redes privadas (WLANs) ou outras redes virtuais privadas. redes (VPNs). .. é ainda mais sensível que o antigo UDID!

ylechelle
fonte
Estou realmente curioso como isso funciona? O código está escrito em Objective-C, mas não há outra solução boa que atenda aos requisitos acima; então, o que torna essa estrutura diferente? A solução que este quadro está usando também deve ser possível postar como uma resposta sugerida aqui ...
jake_hetfield
Concordo - o endereço MAC também pode ser configurado manualmente ("clonado"), embora isso não seja provável na maior parte. Eu devo protestar contra o D no UDID. Este não é um ID do dispositivo, é um UUID (identificador universal universal). O ID do dispositivo é carimbado pela Apple de fábrica em cada dispositivo na ROM.
Jay Imerman
Melhor solução para iOS7 bem que o que é realmente necessário para identificar um dispositivo exclusivamente
Vishal dharankar
1
O OpenUDID está obsoleto e não é recomendado o uso
mkll
11

Tenho certeza que a Apple incomodou muitas pessoas com essa mudança. Desenvolvo um aplicativo de contabilidade para iOS e tenho um serviço online para sincronizar alterações feitas em diferentes dispositivos. O serviço mantém um banco de dados de todos os dispositivos e as alterações que precisam ser propagadas para eles. Portanto, é importante saber quais dispositivos são quais. Estou acompanhando os dispositivos usando o UIDevice uniqueIdentifier e, para o que vale, aqui estão os meus pensamentos.

  • Gerar um UUID e armazenar os padrões do usuário? Não é bom porque isso não persiste quando o usuário exclui o aplicativo. Se eles instalarem novamente mais tarde, o serviço online não deve criar um novo registro de dispositivo, isso desperdiçaria recursos no servidor e forneceria uma lista de dispositivos contendo o mesmo duas ou mais vezes. Os usuários verão mais de um "iPhone de Bob" listado se reinstalarem o aplicativo.

  • Gerar um UUID e armazenar no chaveiro? Esse era meu plano, pois persiste mesmo quando o aplicativo é desinstalado. Mas, ao restaurar um backup do iTunes para um novo dispositivo iOS, as chaves serão transferidas se o backup for criptografado. Isso pode levar a dois dispositivos que contêm a mesma identificação de dispositivo, se os dispositivos antigos e novos estiverem em serviço. Eles devem ser listados como dois dispositivos no serviço online, mesmo que o nome do dispositivo seja o mesmo.

  • Gerar um hash com o endereço MAC e o ID do pacote? Parece a melhor solução para o que eu preciso. Ao fazer o hash com o ID do pacote, o ID do dispositivo gerado não permitirá que o dispositivo seja rastreado nos aplicativos e recebo um ID exclusivo para a combinação de aplicativo + dispositivo.

É interessante notar que a documentação da Apple se refere à validação de recibos da Mac App Store, calculando um hash do endereço MAC do sistema, além do ID e versão do pacote. Portanto, isso parece permitido pela política, seja passando pela revisão do aplicativo que ainda não conheço.

Mathew Waters
fonte
10
Para evitar a situação descrita em seu segundo ponto, defina a acessibilidade do seu item de chaveiro como kSecAttrAccessibleAlwaysThisDeviceOnly. Isso garantirá que seu UUID não seja restaurado para outros dispositivos, mesmo se o backup estiver criptografado.
21412 Jeevan Takhar
Este é realmente o comportamento que já vi muitas vezes. Por exemplo, registro meu iPhone no Google Sync. Então comprei um novo iPhone, registrei-o e pronto - agora tenho 2 iPhones listados nas minhas configurações de Sincronização.
Jay Imerman
11

Parece que no iOS 6, a Apple está recomendando o uso da classe NSUUID .

Na mensagem agora nos documentos do UIDevice para a uniqueIdentifierpropriedade:

Descontinuado no iOS 5.0. Use a propriedade identifierForVendor dessa classe ou a propriedade advertisingIdentifier da classe ASIdentifierManager, conforme apropriado, ou use o método UUID da classe NSUUID para criar um UUID e gravá-lo no banco de dados de padrões do usuário.

Nate
fonte
10

Pode ajudar: use o código abaixo, ele sempre será exclusivo, exceto que você apaga (formata) o seu dispositivo.

UIDevice *myDevice=[UIDevice currentDevice];
NSString *UUID = [[myDevice identifierForVendor] UUIDString];
Ashvin Ajadiya
fonte
1
Eu usei esse código. Mas quando eu apaguei aplicativo e novamente instalado cheguei nova Id
Durgaprasad
1
essa é uma solução simples se você não precisar de um método robusto. Estou usando no meu aplicativo agora.
Reuben L.
@ Durgaprasad: ele sempre muda porque depende do fornecedor. Por exemplo: 1. Se você instalou um aplicativo com bundleidenedifier: com.abcd.com =>, ele será alterado. 2. Se você tiver instalar dois aplicativo com bundleidenedifier: com.abcd.com => Então ele não vai chnage (Mantenha qualquer aplicativo durante)
Ashvin Ajadiya
7

Eu também sugeriria a mudança uniqueIdentifierpara essa biblioteca de código aberto (duas categorias simples) que utilizam o endereço MAC do dispositivo junto com o App Bundle Identifier para gerar um ID exclusivo em seus aplicativos que pode ser usado como um substituto de UDID.

Lembre-se de que, diferentemente do UDID, esse número será diferente para cada aplicativo.

Você só precisa importar os incluídos NSStringe UIDevicecategorias e chamada [[UIDevice currentDevice] uniqueDeviceIdentifier]assim:

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

Você pode encontrá-lo no Github aqui:

UIDevice com UniqueIdentifier para iOS 5


Aqui estão as categorias (apenas os arquivos .m - verifique os cabeçalhos no projeto github):

UIDevice + IdentifierAddition.m

#import "UIDevice+IdentifierAddition.h"
#import "NSString+MD5Addition.h"

#include <sys/socket.h> // Per msqr
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>

@interface UIDevice(Private)

- (NSString *) macaddress;

@end

@implementation UIDevice (IdentifierAddition)

////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Private Methods

// Return the local MAC addy
// Courtesy of FreeBSD hackers email list
// Accidentally munged during previous update. Fixed thanks to erica sadun & mlamb.
- (NSString *) macaddress{
    
    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;
    
    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;
    
    if ((mib[5] = if_nametoindex("en0")) == 0) {
        printf("Error: if_nametoindex error\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }
    
    if ((buf = malloc(len)) == NULL) {
        printf("Could not allocate memory. error!\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2");
        return NULL;
    }
    
    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 
                           *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
    free(buf);
    
    return outstring;
}

////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Public Methods

- (NSString *) uniqueDeviceIdentifier{
    NSString *macaddress = [[UIDevice currentDevice] macaddress];
    NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];  
    NSString *stringToHash = [NSString stringWithFormat:@"%@%@",macaddress,bundleIdentifier];
    NSString *uniqueIdentifier = [stringToHash stringFromMD5];  
    return uniqueIdentifier;
}

- (NSString *) uniqueGlobalDeviceIdentifier{
    NSString *macaddress = [[UIDevice currentDevice] macaddress];
    NSString *uniqueIdentifier = [macaddress stringFromMD5];    
    return uniqueIdentifier;
}

@end

NSString + MD5Addition.m:

#import "NSString+MD5Addition.h"
#import <CommonCrypto/CommonDigest.h>

@implementation NSString(MD5Addition)

- (NSString *) stringFromMD5{
    
    if(self == nil || [self length] == 0)
        return nil;
    
    const char *value = [self UTF8String];
    
    unsigned char outputBuffer[CC_MD5_DIGEST_LENGTH];
    CC_MD5(value, strlen(value), outputBuffer);
    
    NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
        [outputString appendFormat:@"%02x",outputBuffer[count]];
    }
    return [outputString autorelease];
}

@end
chown
fonte
3
A partir do iOS 7, a Apple retornará um valor constante para o endereço MAC. Faz todo o sentido. O endereço MAC é sensível.
27413 Roberto
4

O endereço MAC pode ser falsificado, o que torna essa abordagem inútil para vincular conteúdo a usuários específicos ou implementar recursos de segurança como listas negras.

Após algumas pesquisas, me parece que ficamos sem uma alternativa adequada a partir de agora. Eu realmente espero que a Apple reconsidere sua decisão.

Talvez seja uma boa ideia enviar um e-mail à Apple sobre esse tópico e / ou registrar uma solicitação de bug / recurso sobre isso, pois talvez eles nem estejam cientes das consequências completas para os desenvolvedores.

Toastor
fonte
13
Um ponto válido, no entanto, acredito que o UUID também possa ser falsificado / manipulado em um telefone com jailbreak, de modo que tecnicamente o [UIDevice uniqueIdentifier] existente seja igualmente defeituoso.
Oliver Pearmain
3
Você sempre pode criar um identificador no servidor e salvá-lo no dispositivo. É assim que a maioria dos aplicativos faz isso. Não entendo por que os programadores do iOS precisam de algo especial.
Sulthan
1
O @Sulthan não funciona no iOS porque se você desinstalar um aplicativo, todos os seus dados desaparecem, então não há como garantir um identificador de dispositivo exclusivo dessa maneira.
22412 lkraider #
4
Não se você salvá-lo no chaveiro. De qualquer forma, nunca vi um aplicativo em que isso fosse um problema. Se o aplicativo e os dados foram excluídos, você não precisa do mesmo identificador de dispositivo. Se você deseja identificar o usuário, peça um email a ele.
Sulthan
O acesso ao endereço MAC também foi banido pela Apple na nova versão do iOS;
Ans
4

UIDevice identifierForVendor introduzido no iOS 6 funcionaria para seus propósitos.

identifierForVendoré uma sequência alfanumérica que identifica exclusivamente um dispositivo ao fornecedor do aplicativo. (somente leitura)

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

O valor dessa propriedade é o mesmo para aplicativos provenientes do mesmo fornecedor em execução no mesmo dispositivo. Um valor diferente é retornado para aplicativos no mesmo dispositivo provenientes de diferentes fornecedores e para aplicativos em dispositivos diferentes, em relação ao fornecedor.

Disponível no iOS 6.0 e posterior e declarado em UIDevice.h

Para iOS 5, consulte este link UIDevice-with-UniqueIdentifier-for-iOS-5

Mahendra Liya
fonte
4

Usando o SSKeychain e o código mencionado acima. Aqui está o código para copiar / colar (adicione o módulo 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
fonte
3

O código a seguir ajuda a obter o UDID:

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

Este é o código que estou usando para obter o ID para iOS 5 e 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
fonte
O que você faz sobre o aviso do compilador PerformSelector may cause a leak because its selector is unknown?
Basil Bourque 22/02
Você não pode mais usar o AdvertisingIdentifier para esse fim, pois a Apple o rejeitará. Mais informações: techcrunch.com/2014/02/03/...
codeplasma
2

A partir do iOS 6, temos uma NSUUIDclasse que cumpre a RFC4122

Link da Apple: apple_ref para NSUUID

DShah
fonte
2

O iOS 11 introduziu a estrutura DeviceCheck. Possui uma solução completa para identificar exclusivamente o dispositivo.

Santosh Botre
fonte
1

Uma maneira de obter UDID:

  1. Inicie um servidor Web dentro do aplicativo com duas páginas: uma deve retornar o perfil MobileConfiguration especialmente criado e a outra deve coletar o UDID. Mais informações aqui , aqui e aqui .
  2. Você abre a primeira página no Mobile Safari de dentro do aplicativo e ele o redireciona para Settings.app, solicitando a instalação do perfil de configuração. Depois de instalar o perfil, o UDID é enviado para a segunda página da web e você pode acessá-lo de dentro do aplicativo. (Settings.app tem todos os direitos necessários e regras diferentes da sandbox).

Um exemplo usando 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)
    }
}

Aqui estão os conteúdos 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>

A instalação do perfil falhará (não me importei em implementar uma resposta esperada, consulte a documentação ), mas o aplicativo obterá um UDID correto. E você também deve assinar o mobileconfig .

bzz
fonte
1

Para o Swift 3.0, use o código abaixo.

let deviceIdentifier: String = (UIDevice.current.identifierForVendor?.uuidString)!
NSLog("output is : %@", deviceIdentifier)
Ganesh
fonte
1
O iOS 11 introduziu a estrutura DeviceCheck. Possui uma solução completa para identificar exclusivamente o dispositivo.
Santosh Botre
1

Você pode usar

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

O que é único para o dispositivo em todos os aplicativos.

Dhaval
fonte
0

Se alguém se deparar com essa pergunta, ao procurar uma alternativa. Eu segui essa abordagem na IDManageraula. Esta é uma coleção de diferentes soluções. KeyChainUtil é um invólucro para ler do chaveiro. Você também pode usar o hashed MAC addresscomo um tipo de ID exclusivo.

/*  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
fonte
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;
}
mahesh chowdary
fonte
0

Podemos usar identifierForVendor para ios7,

-(NSString*)uniqueIDForDevice
{
    NSString* uniqueIdentifier = nil;
    if( [UIDevice instancesRespondToSelector:@selector(identifierForVendor)] ) { // >=iOS 7
        uniqueIdentifier = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    } else { //<=iOS6, Use UDID of Device       
            CFUUIDRef uuid = CFUUIDCreate(NULL);
            //uniqueIdentifier = ( NSString*)CFUUIDCreateString(NULL, uuid);- for non- ARC
            uniqueIdentifier = ( NSString*)CFBridgingRelease(CFUUIDCreateString(NULL, uuid));// for ARC
            CFRelease(uuid);
         }
    }
return uniqueIdentifier;
}

--Nota importante ---

UDID e identifierForVendor são diferentes: ---

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
fonte
você tem certeza ? podemos usar identifierForVendor para iOS7?
Avis
0

A Apple ocultou o UDID de todas as APIs públicas, começando no iOS 7. Qualquer UDID que comece com FFFF é um ID falso. Os aplicativos "Enviar UDID" que funcionavam anteriormente não podem mais ser usados ​​para reunir o UDID para dispositivos de teste. (suspiro!)

O UDID é mostrado quando um dispositivo está conectado ao XCode (no organizador) e quando o dispositivo está conectado ao iTunes (embora você precise clicar em 'Número de Série' para exibir o Identificador).

Se você precisar obter o UDID de um dispositivo para adicionar a um perfil de provisionamento e não conseguir fazer isso sozinho no XCode, será necessário orientá-lo nas etapas para copiar / colar o iTunes.

Existe uma maneira desde (versão do iOS 7) de obter o UDID sem usar o iTunes em um PC / Mac?

Preet
fonte
0

Eu também tinha um problema e a solução é simples:

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

Uma alternativa não perfeita, mas uma das melhores e mais próximas alternativas ao UDID (no Swift usando o iOS 8.1 e o Xcode 6.1):

Gerando um UUID aleatório

let strUUID: String = NSUUID().UUIDString

E use a biblioteca KeychainWrapper :

Adicione um valor de sequência ao chaveiro:

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

Recupere um valor de string do chaveiro:

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

Remova um valor de string do chaveiro:

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

Esta solução usa o chaveiro, portanto, o registro armazenado no chaveiro será mantido, mesmo após o aplicativo ser desinstalado e reinstalado. A única maneira de excluir este registro é redefinir todo o conteúdo e configurações do dispositivo. É por isso que mencionei que esta solução de substituição não é perfeita, mas continua sendo uma das melhores soluções de substituição para UDID no iOS 8.1 usando o Swift.

O rei da bruxaria
fonte
0

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

Ankit garg
fonte