Comment puis-je obtenir par programme l'adresse MAC d'un iPhone

144

Comment obtenir par programme l'adresse MAC et l'adresse IP d'un iPhone?

Cœur
la source
Je souhaite obtenir une adresse MAC et une adresse IP par programmation dans une application iPhone.
Adresse MAC Wifi? ou BlueTooth? Il existe de nombreuses adresses Mac.
mskw
11
À 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 ma réponse ci-dessous.
Hejazi
Pour iOS et versions ultérieures (jusqu'à aujourd'hui), reportez-vous à stackoverflow.com/questions/11836225/…
rptwsthi

Réponses:

114

REMARQUE Depuis iOS7, vous ne pouvez plus récupérer les adresses MAC des appareils. Une valeur fixe sera renvoyée plutôt que le MAC réel


Quelque chose sur lequel je suis tombé il y a quelque temps. À l'origine d' ici, je l'ai un peu modifié et nettoyé les choses.

IPAddress.h
IPAddress.c

Et pour l'utiliser

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

Les noms des adaptateurs varient en fonction du simulateur / de l'appareil ainsi que du wifi ou de la cellule de l'appareil.

PyjamaSam
la source
Je me demande juste si c'est différent d'une approche générique d'OS X (je demande parce que je suis un mac n00b)
Tamas Czinege
2
@abc: Je vous recommande de poster une autre question à ce sujet. Mieux vaut alors l'enterrer dans les commentaires pour une question différente.
PyjamaSam
1
mais qu'en est-il de l'appel à ether_ntoa? c'est une API privée, n'est-ce pas?
stigi
1
@NicTesla Je ne peux pas commenter avec certitude, mais comme il ne fait que des appels réseau de base, je ne vois aucun problème. Bien que cela soit dit avec la suppression de l'UDID d'iOS5, l'obtention de l'adresse mac et son utilisation pour développer une sorte d'identifiant unique alternatif pourrait être examinée par Apple à un moment donné dans le futur.
PyjamaSam du
1
En ce qui concerne l' ether_ntoaavertissement, consultez: stackoverflow.com/a/13412265/88597
ohho
45

Mise à jour: cela ne fonctionnera pas sur iOS 7. Vous devez utiliser ASIdentifierManager .


Une solution plus propre sur le site Web de 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;
}
ArtFeel
la source
changez le lien en mobiledevelopertips au lieu de iphonedevelopertips
SEG
Apple est TRÈS susceptible de casser cela dans iOS7 ... et nous ne serons pas en mesure de commenter cela publiquement jusqu'à ce qu'il soit livré, sauf sur les forums officiels Apple Dev.
Gabe
3
Cela n'a pas fonctionné sur mon iPhone5 avec iOS7. Cela me donne: 02: 00: 00: 00: 00: 00 ce qui n'est pas juste.
Sjoerd Perfors
3
@Brenden Vous ne pouvez plus obtenir l'adresse MAC du réseau en utilisant PublicAPI sur iOS7. Donc, si vous avez besoin d'un identifiant unique, vous devriez utiliserIdentifierManager
ArtFeel
2
@SjoerdPerfors Sous iOS 7, vous obtiendrez en effet toujours la même adresse 02:00:00:00:00:00que par mesure de confidentialité d'Apple.
Basil Bourque
31

Je voulais quelque chose pour renvoyer l'adresse, que le wifi soit activé ou non, donc la solution choisie n'a pas fonctionné pour moi. J'ai utilisé un autre appel que j'ai trouvé sur un forum après quelques ajustements. J'ai fini avec ce qui suit (excusez mon C rouillé):

#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;
}

Et puis je l'appellerais demander en0 , comme suit:

char* macAddressString= (char*)malloc(18);
NSString* macAddress= [[NSString alloc] initWithCString:getMacAddress(macAddressString, "en0")
                                              encoding:NSMacOSRomanStringEncoding];
free(macAddressString);
capitaine
la source
9
J'ai dû ajouter #define IFT_ETHER 0x6
teedyay
Celui-ci ne fonctionne pas pour moi ... dit que ifName n'est pas déclaré ainsi que la variable macaddress.
bugfixr
Le code d'appel ci-dessus fuit. gratuit (macAddressString); avant de revenir de la méthode d'appel ci-dessus. De plus, macAddress doit être libéré automatiquement si le code d'appel ci-dessus est dans une autre méthode.
4
pour être clair, le code lui-même ne fuira pas, le commentateur parlait de l'extrait d'appel à la fin, où j'alloue deux chaînes sans les libérer.
shipmaster
1
J'ai mis cela dans une belle méthode objective-c et je l'ai fait pour qu'elle ne nécessite aucun paramètre: gist.github.com/wsidell/5069159
wsidell
23

À 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.

Dans iOS 7 et versions ultérieures, si vous demandez l'adresse MAC d'un appareil iOS, le système renvoie la valeur 02: 00: 00: 00: 00: 00. Si vous devez identifier l'appareil, utilisez plutôt la propriété identifierForVendor d'UIDevice. (Les applications qui ont besoin d'un identifiant pour leurs propres fins publicitaires doivent envisager d'utiliser la propriété advertisingIdentifier d'ASIdentifierManager à la place.) "

Référence: releasenotes

Hejazi
la source
Ce qui est vraiment bien à propos de cette dépréciation dans l'API, c'est qu'elle fonctionne toujours correctement sur le simulateur, et uniquement sur le matériel pour le moment.
John Nye
12

Il existe différentes solutions à ce sujet, mais je n'ai rien trouvé. J'ai donc fait ma propre solution pour:

nicinfo

Comment utiliser :

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!");
}
Kenial
la source
Classe très agréable et utile! Bon travail! Cependant, vous avez manqué [super dealloc] sur les deux classes et oublié d'inclure une bibliothèque, ce qui conduit à des avertissements dans xCode. La version corrigée
Raptor
obtention de ce résultat Adresse Mac: 02: 00: 00: 00: 00: 00
Stalin Pusparaj
1
Oui. Apple a bloqué cela depuis iOS 7 :( ... developer.apple.com/library/content/releasenotes/General/…
Kenial
5

Cela ressemble à une solution assez propre: 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;
}
Grantland à mâcher
la source
1
J'utilise votre solution, 99% des cas fonctionnent bien comme prévu, mais le taux de 1% ne peut pas obtenir l'adresse mac, retourne NULL, signalé par les utilisateurs dans l'AppStore. Vous n'obtenez toujours pas d'étapes reproductibles, l'avez-vous? Je vous remercie.
jianhua
Je n'ai encore remarqué aucun problème, mais je resterai vigilant!
Grantland Chew
Suite au commentaire de @ jianhua: nous venons de recevoir des rapports d'un utilisateur qui ne peut fondamentalement pas utiliser l'application car ce code renvoie null pour son appareil (nous utilisons l'identifiant pour authentifier chaque appel au serveur).
samvermette
Le cas échoué est sur iPhone 4S avec la version IOS 5.0.1, bien sûr, ce n'est que lors d'occasions spéciales.
jianhua
5

Désormais, les appareils iOS 7 renvoient toujours une adresse MAC de 02: 00: 00: 00: 00: 00.

Il vaut donc mieux utiliser [UIDevice identifierForVendor].

il vaut donc mieux appeler cette méthode pour obtenir une clé unique spécifique à l'application

La catégorie sera plus appropriée

importer "UIDevice + Identifier.h"

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

Appelez maintenant la méthode ci-dessus pour obtenir une adresse unique

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

NSLog(@"%@",like_UDID);
Nagendra Tripathi
la source
cet identifiant serait-il cohérent par appareil sur plusieurs installations de la même application?
samsam
4

@Grantland Cette "solution assez propre" ressemble à ma propre amélioration par rapport à la solution iPhoneDeveloperTips.

Vous pouvez voir mon étape ici: 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;
}
Cœur
la source
et je ne comprends pas pourquoi je peux ajouter des commentaires pour mes propres réponses mais pas pour les réponses des autres? : /
Cœur
1
Parce que votre réputation n'est pas assez élevée.
honus
Merci, on dirait que quelques personnes ont proposé
josh-fuggle
1

Ce n'est plus possible sur les appareils exécutant iOS 7.0 ou une version ultérieure, donc indisponible pour obtenir l'adresse MAC dans Swift.

Comme Apple l'a déclaré:

Dans iOS 7 et versions ultérieures, si vous demandez l'adresse MAC d'un appareil iOS, le système renvoie la valeur 02: 00: 00: 00: 00: 00. Si vous devez identifier l'appareil, utilisez plutôt la propriété identifierForVendor d'UIDevice. (Les applications qui ont besoin d'un identifiant pour leurs propres fins publicitaires doivent envisager d'utiliser la propriété advertisingIdentifier d'ASIdentifierManager à la place.)

pedrouan
la source
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;
}
Valentin Shamardin
la source
0

Pour créer un uniqueString basé sur l'identifiant unique de l'appareil dans iOS 6:

#import <AdSupport/ASIdentifierManager.h>

NSString *uniqueString = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
NSLog(@"uniqueString: %@", uniqueString);
Denis Kutlubaev
la source
1
comment cela se rapporte à la question posée?
Valeriy Van
1
L'adresse Mac est nécessaire pour identifier de manière unique l'appareil dans la plupart des cas. Au lieu de cela, vous pouvez utiliser cette solution.
Denis Kutlubaev
0

Beaucoup de ces questions ne concernent que l'adresse Mac. Si vous avez également besoin de l'adresse IP que je viens d'écrire, cela peut nécessiter du travail mais semble bien fonctionner sur ma machine ...

- (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 @"?.?.?.?";
}
Oliver Pearmain
la source