Come posso ottenere a livello di codice l'indirizzo MAC di un iPhone


144

Come ottenere a livello di codice l'indirizzo MAC e l'indirizzo IP di un iPhone?


Voglio ottenere l'indirizzo MAC e l'indirizzo IP a livello di codice in un'applicazione iPhone.

Indirizzo MAC Wifi? o BlueTooth? Ci sono molti indirizzi Mac.
mskw

11
A partire da iOS 7, il sistema restituisce sempre il valore 02:00:00:00:00:00quando si richiede l'indirizzo MAC su qualsiasi dispositivo. Controlla la mia risposta qui sotto.
Hejazi,

Per iOS e fino (ad oggi) si riferiscono stackoverflow.com/questions/11836225/...
rptwsthi

Risposte:


114

NOTA A partire da iOS7, non è più possibile recuperare gli indirizzi MAC del dispositivo. Verrà restituito un valore fisso anziché il MAC effettivo


Qualcosa in cui mi sono imbattuto un po 'di tempo fa. Originariamente da qui l' ho modificato un po 'e ho ripulito le cose.

IPAddress.h
IPAddress.c

E usarlo

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]);
    }
}

I nomi degli adattatori variano in base al simulatore / dispositivo nonché al wifi o alla cella sul dispositivo.


mi chiedo solo se questo è diverso da un approccio OS X generico (lo sto chiedendo perché sono un mac n00b)
Tamas Czinege

2
@abc: ti consiglio di pubblicare un'altra domanda a riguardo. Fai meglio a seppellirlo nei commenti per una domanda diversa.
PyjamaSam,

1
ma per quanto riguarda la chiamata a ether_ntoa? questa è un'API privata, vero?
stigi,

1
@NicTesla Non posso commentare con certezza, ma dal momento che sta facendo semplicemente chiamate di rete di base non riesco a vedere un problema. Tuttavia, detto questo con la rimozione dell'UDID da iOS5 che ottiene l'indirizzo mac e lo usa per sviluppare un qualche tipo di identificatore univoco alternativo potrebbe venire esaminato da Apple ad un certo punto in futuro.
PyjamaSam,

1
Per quanto riguarda ether_ntoaavvertimento, check out: stackoverflow.com/a/13412265/88597
ohho

45

Aggiornamento: questo non funzionerà su iOS 7. Dovresti usare ASIdentifierManager .


Soluzione più pulita sul sito Web 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;
}

cambia il collegamento in mobiledevelopertips anziché in iphonedevelopertips
SEG

È molto probabile che Apple lo rompa in iOS7 ... e non saremmo in grado di commentare pubblicamente fino a quando non verrà spedito ad eccezione dei forum Apple Dev ufficiali.
Gabe,

3
Questo non ha funzionato sul mio iPhone5 con iOS7. Mi dà: 02: 00: 00: 00: 00: 00 che non è giusto.
Sjoerd Perfors,

3
@Brenden Non è più possibile ottenere l'indirizzo MAC di rete utilizzando PublicAPI su iOS7. Quindi, se hai bisogno di un ID unico, dovresti usareIdentifierManager
ArtFeel il

2
@SjoerdPerfors Sotto iOS 7 avrai sempre lo stesso indirizzo 02:00:00:00:00:00di una precauzione sulla privacy di Apple.
Basil Bourque,

31

Volevo che qualcosa restituisse l'indirizzo indipendentemente dal fatto che il wifi fosse abilitato o meno, quindi la soluzione scelta non funzionava per me. Ho usato un'altra chiamata che ho trovato su alcuni forum dopo alcune modifiche. Ho finito con il seguente (scusa la mia C arrugginita):

#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 poi lo chiamerei chiedere en0 , come segue:

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

9
Ho dovuto aggiungere #define IFT_ETHER 0x6
teedyay il

Questo non funziona per me ... dice ifName non è dichiarato così come la variabile macaddress.
bugfixr,

Il codice chiamante sopra perde. libera (macAddressString); prima di tornare dal metodo di chiamata sopra. Inoltre, macAddress deve essere rilasciato automaticamente se il codice chiamante sopra è in un altro metodo.

4
per essere chiari, il codice stesso non perderà, il commentatore stava parlando dello snippet di chiamata alla fine, dove allocare due stringhe senza liberarle.
comandante della nave il

1
Ho messo questo in un bel metodo obiettivo-c e l'ho fatto in modo che non richieda parametri: gist.github.com/wsidell/5069159
wsidell

23

A partire da iOS 7, il sistema restituisce sempre il valore 02:00:00:00:00:00quando si richiede l'indirizzo MAC su qualsiasi dispositivo.

In iOS 7 e versioni successive, se si richiede l'indirizzo MAC di un dispositivo iOS, il sistema restituisce il valore 02: 00: 00: 00: 00: 00. Se è necessario identificare il dispositivo, utilizzare invece la proprietà identifierForVendor di UIDevice. (Le app che necessitano di un identificatore per i propri scopi pubblicitari dovrebbero prendere in considerazione l'utilizzo della proprietà advertisingIdentifier di ASIdentifierManager.) "

Riferimento: rilasci


La cosa davvero bella di questa deprecazione nell'API è che funziona ancora correttamente sul simulatore e al momento solo sull'hardware.
John Nye,

12

Esistono diverse soluzioni a riguardo, ma non sono riuscito a trovare nulla. Quindi ho creato la mia soluzione per:

nicinfo

Come usare :

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 molto bella e utile! Buon lavoro! Tuttavia, hai perso [super dealloc] in entrambe le classi e hai dimenticato di includere una libreria, che porta ad avvertimenti in xCode. La versione corretta può essere trovata qui: raptor.hk/download/NICInfo_raptor_patched.zip
Raptor

ottenere questo risultato Indirizzo Mac: 02: 00: 00: 00: 00: 00
Stalin Pusparaj

1
Sì. Apple lo ha bloccato da iOS 7 :( ... developer.apple.com/library/content/releasenotes/General/…
Kenial

5

Sembra una soluzione abbastanza pulita: 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
Uso la tua soluzione, il 99% dei casi funziona bene come previsto, ma l'1% non riesce a ottenere l'indirizzo mac, restituisce NULL, segnalato dagli utenti in AppStore. Non hai ancora passaggi riproducibili, ce l'hai? Grazie.
jianhua,

Non ho ancora notato alcun problema, ma terrò d'occhio!
Grantland Chew

In seguito al commento di @ jianhua: abbiamo appena ricevuto segnalazioni da un utente che sostanzialmente non può usare l'app perché questo codice restituisce null per il suo dispositivo (usiamo l'identificatore per autenticare ogni chiamata del server).
Samvermette,

Il caso fallito è su iPhone 4S con IOS versione 5.0.1, ovviamente lo è solo in alcune occasioni speciali.
jianhua,

5

Ora i dispositivi iOS 7 - restituiscono sempre un indirizzo MAC di 02: 00: 00: 00: 00: 00.

Quindi meglio usare [UIDevice identifierForVendor].

quindi è meglio chiamare questo metodo per ottenere una chiave univoca specifica per l'app

La categoria sarà più adatta

import "UIDevice + Identifier.h"

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

Ora chiama il metodo sopra per ottenere un indirizzo univoco

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

NSLog(@"%@",like_UDID);

questo identificatore sarebbe coerente per dispositivo su più installazioni della stessa app?
samsam,

4

@Grantland Questa "soluzione abbastanza pulita" è simile al mio miglioramento rispetto alla soluzione iPhoneDeveloperTips.

Puoi vedere il mio passaggio qui: 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 non capisco perché posso aggiungere commenti per le mie risposte ma non per le risposte degli altri? : /
Cœur

1
Perché la tua reputazione non è abbastanza alta.
honus,

Grazie, sembra che alcune persone abbiano escogitato le proprie varianti di questa soluzione: ios.biomsoft.com/2011/11/07/determine-mac-address
josh-fuggle

1

Non è più possibile sui dispositivi che eseguono iOS 7.0 o versioni successive, quindi non disponibile per ottenere l'indirizzo MAC in Swift.

Come ha affermato Apple:

In iOS 7 e versioni successive, se si richiede l'indirizzo MAC di un dispositivo iOS, il sistema restituisce il valore 02: 00: 00: 00: 00: 00. Se è necessario identificare il dispositivo, utilizzare invece la proprietà identifierForVendor di UIDevice. (Le app che necessitano di un identificatore per i propri scopi pubblicitari dovrebbero prendere in considerazione l'utilizzo della proprietà advertisingIdentifier di 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

Per creare un uniqueString basato sull'identificatore univoco del dispositivo in iOS 6:

#import <AdSupport/ASIdentifierManager.h>

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

1
come si collega alla domanda posta?
Valeriy Van,

1
Nella maggior parte dei casi è necessario l'indirizzo Mac per identificare in modo univoco il dispositivo. Invece, puoi usare questa soluzione.
Denis Kutlubaev il

0

Molte di queste domande riguardano solo l'indirizzo Mac. Se hai anche bisogno dell'indirizzo IP che ho appena scritto, potrebbe essere necessario un po 'di lavoro ma sembra funzionare bene sulla mia macchina ...

- (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 @"?.?.?.?";
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.