프로그래밍 방식으로 아이폰의 MAC 주소를 얻는 방법


144

프로그래밍 방식으로 iPhone의 MAC 주소와 IP 주소를 얻는 방법은 무엇입니까?


iPhone 응용 프로그램에서 MAC 주소와 IP 주소를 프로그래밍 방식으로 가져 오려고합니다.

와이파이 MAC 주소? 또는 BlueTooth? 많은 Mac 주소가 있습니다.
mskw 2016 년

11
iOS 7부터 시스템 02:00:00:00:00:00은 모든 장치에서 MAC 주소를 요청할 때 항상 값을 반환합니다 . 아래에서 내 대답을 확인하십시오.
Hejazi 2016 년

ios 및 up (오늘까지)에 대해서는 stackoverflow.com/questions/11836225/…를
rptwsthi

답변:


114

참고 iOS7부터는 더 이상 장치 MAC 주소를 검색 할 수 없습니다. 실제 MAC이 아닌 고정 값이 반환됩니다


나는 얼마 전에 우연히 발견되었습니다. 원래부터 여기 에서 약간 수정하고 정리했습니다.

IPAddress.h
IPAddress.c

그리고 그것을 사용하려면

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

어댑터 이름은 시뮬레이터 / 장치 및 장치의 Wi-Fi 또는 셀에 따라 다릅니다.


이것이 일반적인 OS X 접근 방식과 다른지 궁금합니다 (Mac n00b이기 때문에 묻습니다)
Tamas Czinege

2
@ abc : 그것에 대해 다른 질문을 게시하는 것이 좋습니다. 다른 질문에 대한 의견에 묻어 두는 것이 좋습니다.
PyjamaSam 2016 년

1
그러나 ether_ntoa에 대한 호출은 어떻습니까? 이것은 비공개 API입니까?
stigi

1
@NicTesla 나는 확실히 언급 할 수는 없지만 기본 네트워킹 호출을 수행 한 이후로 문제를 볼 수 없습니다. iOS 5에서 UDID를 제거하여 mac 주소를 가져 와서 다른 종류의 대체 고유 식별자를 개발하는 데 사용한다고 말하면 애플은 나중에 언젠가는 조사를받을 수 있습니다.
PyjamaSam

1
ether_ntoa경고와 관련 하여 다음을 확인하십시오. stackoverflow.com/a/13412265/88597
ohho

45

업데이트 : iOS 7에서는 작동하지 않습니다 . ASIdentifierManager를 사용해야합니다 .


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

iphonedevelopertips 대신 mobiledevelopertips 로의 링크 변경
SEG

애플은 iOS7에서 이것을 깨뜨릴 가능성이 매우 높으며 공식 Apple Dev Forums를 제외하고는 출시 될 때까지 공개적으로 언급 할 수 없습니다.
Gabe

3
iOS7이 설치된 iPhone5에서는 작동하지 않았습니다. 그것은 02 : 00 : 00 : 00 : 00 : 00 나에게 맞지 않습니다.
Sjoerd Perfors

3
@Brenden 더 이상 iOS7에서 PublicAPI를 사용하여 네트워크 MAC 주소를 얻을 수 없습니다. 따라서 고유 한 ID가 필요한 경우IdentifierManager
ArtFeel

2
@SjoerdPerfors iOS 7에서는 항상 02:00:00:00:00:00Apple의 개인 정보 보호 조치 와 동일한 주소를 사용하게 됩니다.
Basil Bourque

31

Wi-Fi 사용 여부에 관계없이 주소를 반환하기를 원했기 때문에 선택한 솔루션이 작동하지 않습니다. 조정 후 일부 포럼에서 찾은 다른 전화를 사용했습니다. 나는 다음과 같이 끝났다 (내 녹슨 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;
}

그런 다음 다음과 같이 en0을 요청하여 호출합니다 .

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

9
나는 #DEFINE IFT_ETHER은 0x6 추가했다
teedyay

이것은 나를 위해 작동하지 않습니다 ... ifName은 macaddress 변수뿐만 아니라 선언되지 않았습니다.
bugfixr

위의 호출 코드가 누출됩니다. 무료 (macAddressString); 위의 호출 메소드에서 돌아 오기 전에. 또한 위의 호출 코드가 다른 메소드에있는 경우 macAddress를 자동 해제해야합니다.

4
분명히하기 위해 코드 자체는 누출되지 않으며 주석자는 마지막에 호출 코드 조각에 대해 이야기했습니다. 여기서 두 문자열을 해제하지 않고 할당합니다.
shipmaster

1
나는 이것을 멋진 objective-c 메소드에 넣고 매개 변수가 필요하지 않도록 만들었습니다. gist.github.com/wsidell/5069159
wsidell

23

iOS 7부터 시스템 02:00:00:00:00:00은 모든 장치에서 MAC 주소를 요청할 때 항상 값을 반환합니다 .

iOS 7 이상에서 iOS 장치의 MAC 주소를 요청하면 시스템은 02 : 00 : 00 : 00 : 00 : 00 값을 반환합니다. 장치를 식별해야하는 경우 대신 UIDevice의 identifierForVendor 속성을 사용하십시오. (자신의 광고 목적으로 식별자가 필요한 앱은 대신 ASIdentifierManager의 AdvertisingIdentifier 속성을 사용해야합니다. ""

참조 : 릴리즈 노트


API에서 이러한 지원 중단에 대해 정말 좋은 점은 시뮬레이터에서 여전히 올바르게 작동하고 현재 하드웨어에서만 작동한다는 것입니다.
John Nye

12

이것에 대한 다양한 해결책이 있지만 모든 것을 찾을 수는 없습니다. 그래서 나는 다음을 위해 나만의 해결책을 만들었다.

nicinfo

사용하는 방법 :

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!");
}

아주 좋고 유용한 수업! 잘 했어! 그러나 두 클래스 모두에서 [super dealloc]을 놓치고 라이브러리를 포함하는 것을 잊었으므로 xCode에 경고가 발생합니다. 패치 버전은 여기에서 찾을 수 있습니다 : raptor.hk/download/NICInfo_raptor_patched.zip
Raptor

이 결과를 얻는 Mac 주소 : 02 : 00 : 00 : 00 : 00 : 00
Stalin Pusparaj

1
예. Apple은 iOS 7부터 이것을 차단했습니다 :( ... developer.apple.com/library/content/releasenotes/General/…
Kenial

5

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
귀하의 솔루션을 사용하지만 99 % 사례가 예상대로 잘 작동하지만 1 % 비율은 Mac 주소를 얻지 못하고 NULL을 반환하며 AppStore의 사용자 가보고합니다. 여전히 재현 가능한 단계를 얻지 못했습니까? 감사합니다.
jianhua

아직 아무 문제도 눈치 채지 못했지만 계속 살펴 보겠습니다!
Grantland Chew

@jianhua의 의견에 이어, 우리는이 코드가 장치에 대해 null을 반환하기 때문에 기본적으로 응용 프로그램을 사용할 수없는 사용자로부터 보고서를 받았습니다 (우리는 모든 서버 호출을 인증하기 위해 식별자를 사용합니다).
samvermette

실패한 사례는 IOS 버전 5.0.1이 설치된 iPhone 4S에서 물론 특별한 경우에만 있습니다.
jianhua

5

이제 iOS 7 기기는 항상 02 : 00 : 00 : 00 : 00 : 00의 MAC 주소를 반환합니다.

[UIDevice identifierForVendor]를 사용하는 것이 좋습니다.

앱 고유의 고유 키를 얻으려면이 메소드를 호출하는 것이 좋습니다.

카테고리가 더 적합합니다

"UIDevice + Identifier.h"가져 오기

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

고유 주소를 얻기 위해 위의 메소드를 호출하십시오.

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

NSLog(@"%@",like_UDID);

이 식별자가 동일한 앱을 여러 번 설치 한 경우 기기별로 일치합니까?
samsam

4

@Grantland이 "정말 깨끗한 솔루션"은 iPhoneDeveloperTips 솔루션에 대한 저의 개선과 비슷합니다.

여기 내 단계를 볼 수 있습니다 : 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

1
당신의 명성이 충분히 높지 않기 때문입니다.
honus

덕분에, 몇 사람과 같은 모양이 솔루션의 자신의 변종과 함께 올라와있다 : ios.biomsoft.com/2011/11/07/determine-mac-address
조쉬 - fuggle

1

iOS 7.0 이상 을 실행하는 기기에서는 더 이상 사용할 수 없으므로 Swift에서 MAC 주소를 가져올 수 없습니다.

애플이 말했듯이 :

iOS 7 이상에서 iOS 장치의 MAC 주소를 요청하면 시스템은 02 : 00 : 00 : 00 : 00 : 00 값을 반환합니다. 장치를 식별해야하는 경우 대신 UIDevice의 identifierForVendor 속성을 사용하십시오. 자체 광고 목적으로 식별자가 필요한 앱은 ASIdentifierManager의 AdvertisingIdentifier 속성을 대신 사용해야합니다.


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

iOS 6에서 기기의 고유 식별자를 기반으로 uniqueString을 만들려면

#import <AdSupport/ASIdentifierManager.h>

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

1
이것이 질문과 어떻게 관련이 있습니까?
Valeriy Van

1
대부분의 경우 장치를 고유하게 식별하려면 Mac 주소가 필요합니다. 대신이 솔루션을 사용할 수 있습니다.
Denis Kutlubaev

0

이러한 질문 중 많은 부분이 Mac 주소에만 해당됩니다. 방금 작성한 IP 주소가 필요한 경우 약간의 작업이 필요할 수 있지만 내 컴퓨터에서 잘 작동하는 것 같습니다 ...

- (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 @"?.?.?.?";
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.