Como obter programaticamente o endereço MAC de um iphone


144

Como obter programaticamente o endereço MAC e o endereço IP de um iPhone?


Quero obter o endereço MAC e o endereço IP programaticamente em um aplicativo para iPhone.

Endereço MAC Wifi? ou BlueTooth? Existem muitos endereços de Mac.
mskw

11
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 minha resposta abaixo.
precisa

Para iOS e para cima (até hoje) referem stackoverflow.com/questions/11836225/...
rptwsthi

Respostas:


114

NOTA No iOS7, você não pode mais recuperar os endereços MAC do dispositivo. Um valor fixo será retornado em vez do MAC real


Algo que me deparei há um tempo atrás. Originalmente daqui , modifiquei um pouco e limpei as coisas.

IPAddress.h
IPAddress.c

E para usá-lo

InitAddresses();
GetIPAddresses();
GetHWAddresses();

int i;
NSString *deviceIP = nil;
for (i=0; i<MAXADDRS; ++i)
{
    static unsigned long localHost = 0x7F000001;        // 127.0.0.1
    unsigned long theAddr;

    theAddr = ip_addrs[i];

    if (theAddr == 0) break;
    if (theAddr == localHost) continue;

    NSLog(@"Name: %s MAC: %s IP: %s\n", if_names[i], hw_addrs[i], ip_names[i]);

        //decided what adapter you want details for
    if (strncmp(if_names[i], "en", 2) == 0)
    {
        NSLog(@"Adapter en has a IP of %s", ip_names[i]);
    }
}

Os nomes dos adaptadores variam dependendo do simulador / dispositivo, bem como do wifi ou da célula no dispositivo.


Eu só quero saber se isso é diferente de uma abordagem X OS genérico (Estou perguntando porque eu sou um n00b mac)
Tamas Czinege

2
@ ABC: Eu recomendo que você publique outra pergunta sobre isso. Seja melhor do que enterrá-lo nos comentários para uma pergunta diferente.
PyjamaSam

1
mas e a chamada para ether_ntoa? isso é API privada, não é?
1113

1
@ NicTesla Não posso comentar com certeza, mas como é apenas fazer chamadas básicas de rede, não vejo problema. Embora isso seja dito com a remoção do UDID do iOS5, obter o endereço mac e usá-lo para desenvolver algum tipo de identificador exclusivo alternativo pode ser examinado pela apple em algum momento no futuro.
PyjamaSam

1
Em relação ether_ntoaaviso, confira: stackoverflow.com/a/13412265/88597
ohho

45

Atualização: isso não funcionará no iOS 7. Você deve usar o ASIdentifierManager .


Solução mais limpa no site MobileDeveloperTips:

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

...

- (NSString *)getMacAddress
{
  int                 mgmtInfoBase[6];
  char                *msgBuffer = NULL;
  size_t              length;
  unsigned char       macAddress[6];
  struct if_msghdr    *interfaceMsgStruct;
  struct sockaddr_dl  *socketStruct;
  NSString            *errorFlag = NULL;

  // Setup the management Information Base (mib)
  mgmtInfoBase[0] = CTL_NET;        // Request network subsystem
  mgmtInfoBase[1] = AF_ROUTE;       // Routing table info
  mgmtInfoBase[2] = 0;              
  mgmtInfoBase[3] = AF_LINK;        // Request link layer information
  mgmtInfoBase[4] = NET_RT_IFLIST;  // Request all configured interfaces

  // With all configured interfaces requested, get handle index
  if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0) 
    errorFlag = @"if_nametoindex failure";
  else
  {
    // Get the size of the data available (store in len)
    if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0) 
      errorFlag = @"sysctl mgmtInfoBase failure";
    else
    {
      // Alloc memory based on above call
      if ((msgBuffer = malloc(length)) == NULL)
        errorFlag = @"buffer allocation failure";
      else
      {
        // Get system information, store in buffer
        if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
          errorFlag = @"sysctl msgBuffer failure";
      }
    }
  }

  // Befor going any further...
  if (errorFlag != NULL)
  {
    NSLog(@"Error: %@", errorFlag);
    return errorFlag;
  }

  // Map msgbuffer to interface message structure
  interfaceMsgStruct = (struct if_msghdr *) msgBuffer;

  // Map to link-level socket structure
  socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);

  // Copy link layer address data in socket structure to an array
  memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6);

  // Read from char array into a string object, into traditional Mac address format
  NSString *macAddressString = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", 
                                macAddress[0], macAddress[1], macAddress[2], 
                                macAddress[3], macAddress[4], macAddress[5]];
  NSLog(@"Mac Address: %@", macAddressString);

  // Release the buffer memory
  free(msgBuffer);

  return macAddressString;
}

mudar o link para mobiledevelopertips em vez de iphonedevelopertips
SEG

É muito provável que a Apple resolva isso no iOS7 ... e não poderíamos comentar isso publicamente até que seja lançado, exceto nos Fóruns oficiais da Apple Dev.
Gabe

3
Isso não funcionou no meu iPhone5 com iOS7. Dá-me: 02: 00: 00: 00: 00: 00, o que não está certo.
Sjoerd Perfors

3
@Brenden Não é possível obter o endereço MAC da rede usando o PublicAPI no iOS7. Então, se você precisar de identificação única, você deve usarIdentifierManager
ArtFeel

2
@SjoerdPerfors No iOS 7, você sempre obterá o mesmo endereço de 02:00:00:00:00:00precaução de privacidade da Apple.
Basil Bourque

31

Eu queria algo para retornar o endereço, independentemente de o wifi estar ativado ou não, para que a solução escolhida não funcionasse para mim. Eu usei outra ligação que encontrei em algum fórum depois de alguns ajustes. Acabei com o seguinte (desculpe meu enferrujado C):

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <net/if_dl.h>
#include <ifaddrs.h>


char*  getMacAddress(char* macAddress, char* ifName) {

int  success;
struct ifaddrs * addrs;
struct ifaddrs * cursor;
const struct sockaddr_dl * dlAddr;
const unsigned char* base;
int i;

success = getifaddrs(&addrs) == 0;
if (success) {
    cursor = addrs;
    while (cursor != 0) {
        if ( (cursor->ifa_addr->sa_family == AF_LINK)
            && (((const struct sockaddr_dl *) cursor->ifa_addr)->sdl_type == IFT_ETHER) && strcmp(ifName,  cursor->ifa_name)==0 ) {
            dlAddr = (const struct sockaddr_dl *) cursor->ifa_addr;
            base = (const unsigned char*) &dlAddr->sdl_data[dlAddr->sdl_nlen];
            strcpy(macAddress, ""); 
            for (i = 0; i < dlAddr->sdl_alen; i++) {
                if (i != 0) {
                    strcat(macAddress, ":");
                }
                char partialAddr[3];
                sprintf(partialAddr, "%02X", base[i]);
                strcat(macAddress, partialAddr);

            }
        }
        cursor = cursor->ifa_next;
    }

    freeifaddrs(addrs);
}    
return macAddress;
}

E então eu chamaria de en0 , da seguinte maneira:

char* macAddressString= (char*)malloc(18);
NSString* macAddress= [[NSString alloc] initWithCString:getMacAddress(macAddressString, "en0")
                                              encoding:NSMacOSRomanStringEncoding];
free(macAddressString);

9
Eu tive que adicionar #define IFT_ETHER 0x6
teedyay

Este não funciona para mim ... diz que ifName não é declarado, assim como a variável macaddress.
bugfixr

O código de chamada acima vazará. free (macAddressString); antes de retornar do método de chamada acima. Além disso, o macAddress deve ser liberado automaticamente se o código de chamada acima estiver em outro método.

4
para ficar claro, o código em si não vazará, o comentarista estava falando sobre o trecho de chamada no final, onde aloco duas strings sem liberá-las.
shipmaster

1
Coloquei isso em um bom método de objetivo-c e fiz com que ele não exija parâmetros: gist.github.com/wsidell/5069159
wsidell

23

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.

No iOS 7 e posterior, se você solicitar o endereço MAC de um dispositivo iOS, o sistema retornará o valor 02: 00: 00: 00: 00: 00. Se você precisar identificar o dispositivo, use a propriedade identifierForVendor do UIDevice. (Os aplicativos que precisam de um identificador para seus próprios fins publicitários devem considerar o uso da propriedade advertisingIdentifier do ASIdentifierManager.) "

Referência: releasenotes


O que é realmente bom sobre essa depreciação na API é que ela ainda funciona no simulador corretamente e apenas no hardware no momento.
precisa

12

Existem várias soluções sobre isso, mas não consegui encontrar nada. Então, eu fiz minha própria solução para:

nicinfo

Como usar :

NICInfoSummary* summary = [[[NICInfoSummary alloc] init] autorelease];

// en0 is for WiFi 
NICInfo* wifi_info = [summary findNICInfo:@"en0"];

// you can get mac address in 'XX-XX-XX-XX-XX-XX' form
NSString* mac_address = [wifi_info getMacAddressWithSeparator:@"-"];

// ip can be multiple
if(wifi_info.nicIPInfos.count > 0)
{
    NICIPInfo* ip_info = [wifi_info.nicIPInfos objectAtIndex:0];
    NSString* ip = ip_info.ip;
    NSString* netmask = ip_info.netmask;
    NSString* broadcast_ip = ip_info.broadcastIP;
}
else
{
    NSLog(@"WiFi not connected!");
}

Classe muito agradável e útil! Bom trabalho! No entanto, você perdeu [super-desassociação] das duas classes e esqueceu de incluir uma biblioteca, o que leva a avisos no xCode. A versão corrigida pode ser encontrada aqui: raptor.hk/download/NICInfo_raptor_patched.zip
Raptor

obtendo este resultado Endereço do Mac: 02: 00: 00: 00: 00: 00
Stalin Pusparaj

1
Sim. A Apple bloqueou isso desde o iOS 7 :( ... developer.apple.com/library/content/releasenotes/General/…
Kenial

5

Parece uma solução bastante limpa: UIDevice BIdentifier

// 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");
        free(buf);
        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;
}

1
Eu uso sua solução, 99% dos casos funcionam bem como o esperado, mas a taxa de 1% não pode obter o endereço mac, retornar NULL, relatado pelos usuários na AppStore. Ainda não obtém etapas reproduzíveis, você entendeu? Obrigado.
Jianhua

Ainda não notei nenhum problema, mas vou ficar de olho!
quer

Seguindo o comentário de @ jianhua: acabamos de receber relatórios de um usuário que basicamente não pode usar o aplicativo porque esse código retorna nulo para o dispositivo (usamos o identificador para autenticar todas as chamadas de servidor).
samvermette

O caso com falha está no iPhone 4S com o IOS versão 5.0.1, é claro que é apenas em algumas ocasiões especiais.
Jianhua

5

Agora dispositivos iOS 7 - sempre retornam um endereço MAC de 02: 00: 00: 00: 00: 00.

Então, use melhor [UIDevice identifierForVendor].

então é melhor chamar esse método para obter uma chave exclusiva específica do aplicativo

Categoria será mais adequado

importar "UIDevice + Identifier.h"

- (NSString *) identifierForVendor1
{
    if ([[UIDevice currentDevice] respondsToSelector:@selector(identifierForVendor)]) {
        return [[[UIDevice currentDevice] identifierForVendor] UUIDString];
    }
    return @"";
}

Agora chame o método acima para obter um endereço exclusivo

NSString *like_UDID=[NSString stringWithFormat:@"%@",
                [[UIDevice currentDevice] identifierForVendor1]];

NSLog(@"%@",like_UDID);

esse identificador seria consistente por dispositivo em várias instalações do mesmo aplicativo?
samsam

4

@Grantland Esta "solução bastante limpa" é semelhante à minha própria melhoria em relação à solução iPhoneDeveloperTips.

Você pode ver minha etapa aqui: https://gist.github.com/1409855/

/* Original source code courtesy John from iOSDeveloperTips.com */

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

+ (NSString *)getMacAddress
{
    int                 mgmtInfoBase[6];
    char                *msgBuffer = NULL;
    NSString            *errorFlag = NULL;
    size_t              length;

    // Setup the management Information Base (mib)
    mgmtInfoBase[0] = CTL_NET;        // Request network subsystem
    mgmtInfoBase[1] = AF_ROUTE;       // Routing table info
    mgmtInfoBase[2] = 0;              
    mgmtInfoBase[3] = AF_LINK;        // Request link layer information
    mgmtInfoBase[4] = NET_RT_IFLIST;  // Request all configured interfaces

    // With all configured interfaces requested, get handle index
    if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0) 
        errorFlag = @"if_nametoindex failure";
    // Get the size of the data available (store in len)
    else if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0) 
        errorFlag = @"sysctl mgmtInfoBase failure";
    // Alloc memory based on above call
    else if ((msgBuffer = malloc(length)) == NULL)
        errorFlag = @"buffer allocation failure";
    // Get system information, store in buffer
    else if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
    {
        free(msgBuffer);
        errorFlag = @"sysctl msgBuffer failure";
    }
    else
    {
        // Map msgbuffer to interface message structure
        struct if_msghdr *interfaceMsgStruct = (struct if_msghdr *) msgBuffer;

        // Map to link-level socket structure
        struct sockaddr_dl *socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);

        // Copy link layer address data in socket structure to an array
        unsigned char macAddress[6];
        memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6);

        // Read from char array into a string object, into traditional Mac address format
        NSString *macAddressString = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
                                      macAddress[0], macAddress[1], macAddress[2], macAddress[3], macAddress[4], macAddress[5]];
        NSLog(@"Mac Address: %@", macAddressString);

        // Release the buffer memory
        free(msgBuffer);

        return macAddressString;
    }

    // Error...
    NSLog(@"Error: %@", errorFlag);

    return nil;
}

e não entendo por que posso adicionar comentários para minhas próprias respostas, mas não para as respostas de outras pessoas? : /
Coeur

1
Porque sua reputação não é alta o suficiente.
honus

Obrigado, parece que algumas pessoas criaram suas próprias variantes desta solução: ios.biomsoft.com/2011/11/07/determine-mac-address
josh-Fuggle

1

Não é mais possível em dispositivos com iOS 7.0 ou posterior, portanto, indisponíveis para obter o endereço MAC no Swift.

Como a Apple afirmou:

No iOS 7 e posterior, se você solicitar o endereço MAC de um dispositivo iOS, o sistema retornará o valor 02: 00: 00: 00: 00: 00. Se você precisar identificar o dispositivo, use a propriedade identifierForVendor do UIDevice. Os aplicativos que precisam de um identificador para seus próprios fins de publicidade devem considerar o uso da propriedade advertisingIdentifier do ASIdentifierManager.


0
#import <sys/socket.h>
#import <net/if_dl.h>
#import <ifaddrs.h>
#import <sys/xattr.h>
#define IFT_ETHER 0x6

...

- (NSString*)macAddress
{
    NSString* result = nil;

    char* macAddressString = (char*)malloc(18);
    if (macAddressString != NULL)
    {
        strcpy(macAddressString, "");

        struct ifaddrs* addrs = NULL;
        struct ifaddrs* cursor;

        if (getifaddrs(&addrs) == 0)
        {
            cursor = addrs;

            while (cursor != NULL)
            {
                if ((cursor->ifa_addr->sa_family == AF_LINK) && (((const struct sockaddr_dl*)cursor->ifa_addr)->sdl_type == IFT_ETHER) && strcmp("en0", cursor->ifa_name) == 0)
                {
                    const struct sockaddr_dl* dlAddr = (const struct sockaddr_dl*) cursor->ifa_addr;
                    const unsigned char* base = (const unsigned char*)&dlAddr->sdl_data[dlAddr->sdl_nlen];

                    for (NSInteger index = 0; index < dlAddr->sdl_alen; index++)
                    {
                        char partialAddr[3];

                        sprintf(partialAddr, "%02X", base[index]);
                        strcat(macAddressString, partialAddr);
                    }
                }

                cursor = cursor->ifa_next;
            }

        }

        result = [[[NSString alloc] initWithUTF8String:macAddressString] autorelease];

        free(macAddressString);
    }

    return result;
}

0

Para criar uma string exclusiva com base no identificador exclusivo do dispositivo no iOS 6:

#import <AdSupport/ASIdentifierManager.h>

NSString *uniqueString = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
NSLog(@"uniqueString: %@", uniqueString);

1
como isso se relaciona com a pergunta feita?
precisa

1
O endereço Mac é necessário para identificar o dispositivo de forma exclusiva na maioria dos casos. Em vez disso, você pode usar esta solução.
Denis Kutlubaev

0

Muitas dessas perguntas abordam apenas o endereço Mac. Se você também precisar do endereço IP que acabei de escrever, pode precisar de algum trabalho, mas parece funcionar bem na minha máquina ...

- (NSString *)getLocalIPAddress
{
    NSArray *ipAddresses = [[NSHost currentHost] addresses];
    NSArray *sortedIPAddresses = [ipAddresses sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];

    NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
    numberFormatter.allowsFloats = NO;

    for (NSString *potentialIPAddress in sortedIPAddresses)
    {
        if ([potentialIPAddress isEqualToString:@"127.0.0.1"]) {
            continue;
        }

        NSArray *ipParts = [potentialIPAddress componentsSeparatedByString:@"."];

        BOOL isMatch = YES;

        for (NSString *ipPart in ipParts) {
            if (![numberFormatter numberFromString:ipPart]) {
                isMatch = NO;
                break;
            }
        }
        if (isMatch) {
            return potentialIPAddress;
        }
    }

    // No IP found
    return @"?.?.?.?";
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.