Jak programowo uzyskać adres MAC telefonu iPhone

144

Jak programowo uzyskać adres MAC i adres IP iPhone'a?

Cœur
źródło
Chcę uzyskać adres MAC i adres IP programowo w aplikacji na iPhone'a.
Adres MAC Wi-Fi? lub BlueTooth? Istnieje wiele adresów Mac.
mskw,
11
Począwszy od iOS 7, system zawsze zwraca wartość, 02:00:00:00:00:00gdy pytasz o adres MAC na dowolnym urządzeniu. Sprawdź moją odpowiedź poniżej.
Hejazi
Dla ios i
nowszych

Odpowiedzi:

114

UWAGA Od iOS7 nie można już pobierać adresów MAC urządzeń. Zwrócona zostanie stała wartość zamiast rzeczywistego adresu MAC


Coś, na co natknąłem się jakiś czas temu. Pierwotnie stąd trochę go zmodyfikowałem i uporządkowałem.

IPAddress.h
IPAddress.c

I użyć go

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

Nazwy adapterów różnią się w zależności od symulatora / urządzenia, a także sieci Wi-Fi lub komórki w urządzeniu.

PyjamaSam
źródło
zastanawiam się tylko, czy to różni się od ogólnego podejścia do OS X (pytam, ponieważ jestem mac n00b)
Tamas Czinege
2
@abc: Polecam zadać kolejne pytanie na ten temat. Lepiej będzie, jeśli pochowaj to w komentarzach pod innym pytaniem.
PyjamaSam
1
ale co z wywołaniem ether_ntoa? to jest prywatny interfejs API, prawda?
stigi
1
@NicTesla Nie mogę komentować na pewno, ale ponieważ wykonuje tylko podstawowe połączenia sieciowe, nie widzę problemu. Chociaż to powiedziawszy po usunięciu identyfikatora UDID z iOS5, uzyskaniu adresu mac i wykorzystaniu go do opracowania alternatywnego unikalnego identyfikatora, firma Apple może w pewnym momencie w przyszłości zbadać sprawę.
PyjamaSam
1
Odnośnie ether_ntoaostrzeżenia, sprawdź: stackoverflow.com/a/13412265/88597
ohho
45

Aktualizacja: to nie zadziała na iOS 7. Powinieneś użyć ASIdentifierManager .


Bardziej przejrzyste rozwiązanie na stronie 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
źródło
zmień link na mobiledevelopertips zamiast iphonedevelopertips
SEG
Apple jest BARDZO prawdopodobne, że zepsuje to w iOS7 ... i nie moglibyśmy tego publicznie komentować, dopóki nie zostanie opublikowany, z wyjątkiem oficjalnych forów Apple Dev.
Gabe
3
To nie zadziałało na moim iPhonie5 z iOS7. Daje mi to: 02: 00: 00: 00: 00: 00, co nie jest w porządku.
Sjoerd Perfors
3
@Brenden Nie można już uzyskać sieciowego adresu MAC za pomocą PublicAPI na iOS7. Więc jeśli potrzebujesz unikalnego identyfikatora, powinieneś użyćIdentifierManager
ArtFeel
2
@SjoerdPerfors W systemie iOS 7 rzeczywiście zawsze otrzymasz ten sam adres, 02:00:00:00:00:00co zabezpieczenie prywatności firmy Apple.
Basil Bourque
31

Chciałem, żeby coś zwróciło adres, niezależnie od tego, czy włączone było wifi, czy nie, więc wybrane rozwiązanie nie zadziałało. Użyłem innego połączenia, które znalazłem na jakimś forum po pewnych poprawkach. Skończyło się na tym (przepraszam mój zardzewiały 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;
}

A potem nazwałbym to prosząc o en0 w następujący sposób:

char* macAddressString= (char*)malloc(18);
NSString* macAddress= [[NSString alloc] initWithCString:getMacAddress(macAddressString, "en0")
                                              encoding:NSMacOSRomanStringEncoding];
free(macAddressString);
kapitan statku
źródło
9
Musiałem dodać #define IFT_ETHER 0x6
teedyay
Ten nie działa dla mnie ... mówi, że ifName nie jest zadeklarowana, podobnie jak zmienna macaddress.
bugfixr
Powyższy kod wywołujący wycieknie. wolne (macAddressString); przed powrotem z powyższej metody wywołania. Ponadto adres macAddress powinien być automatycznie udostępniany, jeśli powyższy kod wywołujący znajduje się w innej metodzie.
4
żeby było jasne, sam kod nie wycieknie, komentator mówił o fragmencie wywołującym na końcu, gdzie przydzielam dwa stringi bez ich zwalniania.
kapitan statku
1
Umieściłem to w ładnej metodzie obiektywnej c i sprawiłem,
wsidell
23

Począwszy od iOS 7, system zawsze zwraca wartość, 02:00:00:00:00:00gdy pytasz o adres MAC na dowolnym urządzeniu.

W systemie iOS 7 i nowszych, jeśli poprosisz o adres MAC urządzenia iOS, system zwróci wartość 02: 00: 00: 00: 00: 00. Jeśli chcesz zidentyfikować urządzenie, użyj zamiast tego właściwości identifierForVendor UIDevice. (Aplikacje, które potrzebują identyfikatora do własnych celów reklamowych, powinny zamiast tego rozważyć użycie właściwości advertisingIdentifier ASIdentifierManager) ”.

Odniesienie: releaseasenotes

Hejazi
źródło
Naprawdę fajne w tym wycofaniu w API jest to, że nadal działa poprawnie na symulatorze i tylko na sprzęcie w tej chwili.
John Nye
12

Istnieje wiele rozwiązań w tej sprawie, ale nie mogłem znaleźć całości. Dlatego stworzyłem własne rozwiązanie dla:

nicinfo

Jak używać :

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
źródło
Bardzo fajna i przydatna klasa! Dobra robota! Jednak przegapiłeś [super dealloc] na obu klasach i zapomniałeś dołączyć bibliotekę, co prowadzi do ostrzeżeń w xCode. Poprawioną wersję można znaleźć tutaj: raptor.hk/download/NICInfo_raptor_patched.zip
Raptor
uzyskiwanie tego wyniku Adres Mac: 02: 00: 00: 00: 00: 00
Stalin Pusparaj
1
Tak. Apple zablokowało to od czasu iOS 7 :( ... developer.apple.com/library/content/releasenotes/General/…
Kenial
5

To wygląda na całkiem czyste rozwiązanie: 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 Chew
źródło
1
Korzystam z twojego rozwiązania, 99% przypadków działa zgodnie z oczekiwaniami, ale 1% stawki nie może uzyskać adresu MAC, zwrócić NULL, zgłoszone przez użytkowników w AppStore. Nadal nie można uzyskać powtarzalnych kroków, czy masz to? Dziękuję Ci.
jianhua
Nie zauważyłem jeszcze żadnych problemów, ale będę uważać!
Grantland Chew
W związku z komentarzem @ jianhua: właśnie otrzymaliśmy raporty od użytkownika, który w zasadzie nie może korzystać z aplikacji, ponieważ ten kod zwraca wartość null dla swojego urządzenia (używamy identyfikatora do uwierzytelniania każdego wywołania serwera).
samvermette
Nieudany przypadek znajduje się na iPhonie 4S z systemem IOS w wersji 5.0.1, oczywiście tylko przy niektórych specjalnych okazjach.
jianhua,
5

Teraz urządzenia iOS 7 - zawsze zwracają adres MAC 02: 00: 00: 00: 00: 00.

Więc lepiej użyj [UIDevice identifierForVendor].

więc lepiej wywołać tę metodę, aby uzyskać unikalny klucz specyficzny dla aplikacji

Kategoria będzie bardziej odpowiednia

import „UIDevice + Identifier.h”

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

Teraz wywołaj powyższą metodę, aby uzyskać unikalny adres

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

NSLog(@"%@",like_UDID);
Nagendra Tripathi
źródło
czy ten identyfikator byłby spójny dla każdego urządzenia w przypadku wielu instalacji tej samej aplikacji?
samsam
4

@Grantland To "całkiem czyste rozwiązanie" wygląda podobnie do mojego własnego ulepszenia w stosunku do rozwiązania iPhoneDeveloperTips.

Możesz zobaczyć mój krok tutaj: 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
źródło
i nie rozumiem, dlaczego mogę dodawać komentarze do własnych odpowiedzi, ale nie do odpowiedzi innych? : /
Cœur
1
Ponieważ twoja reputacja nie jest wystarczająco wysoka.
honus
Dzięki, wygląda na to, że kilka osób wymyśliło własne warianty tego rozwiązania: ios.biomsoft.com/2011/11/07/determine-mac-address
josh-fuggle
1

Nie jest już możliwe na urządzeniach z systemem iOS 7.0 lub nowszym, dlatego nie można uzyskać adresu MAC w Swift.

Jak stwierdził Apple:

W systemie iOS 7 i nowszych, jeśli poprosisz o adres MAC urządzenia iOS, system zwróci wartość 02: 00: 00: 00: 00: 00. Jeśli chcesz zidentyfikować urządzenie, użyj zamiast tego właściwości identifierForVendor UIDevice. (Aplikacje, które potrzebują identyfikatora do własnych celów reklamowych, powinny zamiast tego rozważyć użycie właściwości advertisingIdentifier ASIdentifierManager).

pedrouan
źródło
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
źródło
0

Aby utworzyć unikalny ciąg na podstawie unikalnego identyfikatora urządzenia w iOS 6:

#import <AdSupport/ASIdentifierManager.h>

NSString *uniqueString = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
NSLog(@"uniqueString: %@", uniqueString);
Denis Kutlubaev
źródło
1
jak to się ma do zadanego pytania?
Valeriy Van
1
W większości przypadków do jednoznacznej identyfikacji urządzenia potrzebny jest adres Mac. Zamiast tego możesz skorzystać z tego rozwiązania.
Denis Kutlubaev
0

Wiele z tych pytań dotyczy tylko adresu Mac. Jeśli potrzebujesz również adresu IP, który właśnie napisałem, może wymagać trochę pracy, ale wydaje się, że działa dobrze na moim komputerze ...

- (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
źródło