Làm cách nào để lập trình địa chỉ MAC của iphone


144

Làm thế nào để lập trình lấy địa chỉ MAC và địa chỉ IP của iPhone?


tôi muốn lấy địa chỉ MAC và địa chỉ IP theo chương trình trong một ứng dụng iPhone.

Địa chỉ MAC MAC? hay BlueTooth? Có nhiều địa chỉ Mac.
mskw

11
Bắt đầu từ iOS 7, hệ thống luôn trả về giá trị 02:00:00:00:00:00khi bạn yêu cầu địa chỉ MAC trên bất kỳ thiết bị nào. Kiểm tra câu trả lời của tôi dưới đây.
Hejazi

Đối với ios trở lên (cho đến hôm nay), hãy tham khảo stackoverflow.com/questions/11836225/
triệt

Câu trả lời:


114

LƯU Ý Kể từ iOS7, bạn không còn có thể truy xuất địa chỉ MAC của thiết bị. Một giá trị cố định sẽ được trả về thay vì MAC thực tế


Một cái gì đó tôi tình cờ thấy một lúc trước. Ban đầu từ đây tôi đã sửa đổi nó một chút và dọn dẹp mọi thứ.

Địa chỉ IP
IPAddress.c

Và để sử dụng nó

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

Tên bộ điều hợp khác nhau tùy thuộc vào trình giả lập / thiết bị cũng như wifi hoặc di động trên thiết bị.


Tôi chỉ tự hỏi liệu điều này có khác với cách tiếp cận OS X chung không (tôi đang hỏi vì tôi là mac n00b)
Tamas Czinege

2
@abc: Tôi khuyên bạn nên đăng một câu hỏi khác về điều đó. Hãy tốt hơn sau đó chôn nó trong các ý kiến ​​cho một câu hỏi khác.
PyjamaSam

1
Nhưng còn cuộc gọi đến ether_ntoa thì sao? Đây là API riêng phải không?
stigi

1
@NicTesla Tôi không thể nhận xét chắc chắn, nhưng vì nó chỉ thực hiện các cuộc gọi mạng cơ bản nên tôi không thể thấy vấn đề. Mặc dù điều đó được nói với việc loại bỏ UDID khỏi iOS5 để lấy địa chỉ mac và sử dụng nó để phát triển một số loại định danh duy nhất thay thế có thể bị xem xét bởi apple vào một thời điểm nào đó trong tương lai.
PyjamaSam

1
Về ether_ntoacảnh báo, hãy xem: stackoverflow.com/a/13412265/88597
ohho

45

Cập nhật: điều này sẽ không hoạt động trên iOS 7. Bạn nên sử dụng ASIdentifierManager .


Giải pháp sạch hơn trên trang 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;
}

thay đổi liên kết đến mobiledevelopertips thay vì iphiatedevelopertips
SEG

Apple rất có thể sẽ phá vỡ điều này trong iOS7 ... và chúng tôi sẽ không thể nhận xét về điều này một cách công khai cho đến khi nó được phát hành ngoại trừ trên Diễn đàn chính thức của Apple Dev.
Gabe

3
Điều này không hoạt động trên iPhone5 của tôi với iOS7. Nó cho tôi: 02: 00: 00: 00: 00 không đúng.
Sjoerd Perfors

3
@Brenden Bạn không thể nhận địa chỉ MAC mạng bằng PublicAPI trên iOS7 nữa. Vì vậy, nếu bạn cần id duy nhất, bạn nên sử dụngIdentifierManager
ArtFeel

2
@SjoerdPerfors Trong iOS 7, bạn thực sự sẽ luôn nhận được cùng một địa chỉ 02:00:00:00:00:00như một biện pháp phòng ngừa quyền riêng tư của Apple.
Basil Bourque

31

Tôi muốn một cái gì đó trả về địa chỉ bất kể có bật wifi hay không, vì vậy giải pháp được chọn không phù hợp với tôi. Tôi đã sử dụng một cuộc gọi khác mà tôi tìm thấy trên một số diễn đàn sau khi điều chỉnh. Tôi đã kết thúc với những điều sau đây (xin lỗi C gỉ của tôi):

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

Và sau đó tôi sẽ gọi nó là yêu cầu en0 , như sau:

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

9
Tôi đã phải thêm #define IFT_ETHER 0x6
teedyay

Cái này không hoạt động với tôi ... nói ifName không được khai báo cũng như biến macaddress.
bugfixr

Các mã gọi trên sẽ bị rò rỉ. miễn phí (macAddressString); trước khi trở về từ phương thức gọi trên. Ngoài ra, macAddress nên được tự động phát hành nếu mã cuộc gọi ở trên là trong một phương thức khác.

4
để rõ ràng, bản thân mã sẽ không bị rò rỉ, người bình luận đã nói về đoạn mã cuộc gọi ở cuối, nơi tôi phân bổ hai chuỗi mà không giải phóng chúng.
tàu

1
Tôi đưa phương thức này vào một phương thức object
wsidell

23

Bắt đầu từ iOS 7, hệ thống luôn trả về giá trị 02:00:00:00:00:00khi bạn yêu cầu địa chỉ MAC trên bất kỳ thiết bị nào.

Trong iOS 7 trở lên, nếu bạn hỏi địa chỉ MAC của thiết bị iOS, hệ thống sẽ trả về giá trị 02: 00: 00: 00: 00: 00. Nếu bạn cần xác định thiết bị, thay vào đó, hãy sử dụng thuộc tính định danhForVendor của UIDevice. (Các ứng dụng cần một mã định danh cho mục đích quảng cáo của riêng họ nên xem xét sử dụng thuộc tính AdvertisingIdentifier của ASIdentifierManager.) "

Tham khảo: phát hành


Điều thực sự hay về sự phản đối này trong API là nó vẫn hoạt động chính xác trên trình giả lập và chỉ trên phần cứng vào lúc này.
John Nye

12

Có nhiều giải pháp khác nhau về vấn đề này, nhưng tôi không thể tìm thấy toàn bộ. Vì vậy, tôi đã thực hiện giải pháp của riêng mình cho:

thông tin

Cách sử dụng:

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

Lớp học rất hay và hữu ích! Làm tốt lắm! Tuy nhiên, bạn đã bỏ lỡ [super dealloc] trên cả hai lớp và quên bao gồm một thư viện, dẫn đến cảnh báo trong xCode. Phiên bản vá có thể được tìm thấy ở đây: raptor.hk/doad/NICInfo_raptor_patched.zip
Raptor

nhận được kết quả này Địa chỉ Mac: 02: 00: 00: 00: 00
Stalin Pusparaj

1
Đúng. Apple đã chặn điều này kể từ iOS 7 :( ... developer.apple.com/l
Library / content / releasenotes / General / từ

5

Đây có vẻ là một giải pháp khá sạch: 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
Tôi sử dụng giải pháp của bạn, 99% trường hợp hoạt động tốt như mong đợi, nhưng tỷ lệ 1% không thể nhận địa chỉ mac, trả về NULL, được báo cáo bởi người dùng trong AppStore. Vẫn không có được các bước tái sản xuất, bạn đã có nó? Cảm ơn bạn.
jianhua

Tôi chưa nhận thấy bất kỳ vấn đề nào, nhưng tôi sẽ theo dõi!
Grantland nhai

Theo dõi bình luận của @ jianhua: chúng tôi vừa nhận được báo cáo từ người dùng về cơ bản không thể sử dụng ứng dụng vì mã này trả về null cho thiết bị của anh ấy (chúng tôi sử dụng mã định danh để xác thực mọi cuộc gọi máy chủ).
samvermette

Trường hợp thất bại là trên iPhone 4S với phiên bản iOS 5.0.1, tất nhiên nó chỉ trong một số dịp đặc biệt.
jianhua

5

Bây giờ các thiết bị iOS 7 - luôn trả về địa chỉ MAC là 02: 00: 00: 00: 00: 00.

Vì vậy, sử dụng tốt hơn [UIDevice định danhForVendor].

tốt hơn hết là gọi phương thức này để lấy khóa duy nhất của ứng dụng

Danh mục sẽ phù hợp hơn

nhập "UIDevice + Định danh.h"

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

Bây giờ gọi phương thức trên để có được địa chỉ duy nhất

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

NSLog(@"%@",like_UDID);

số nhận dạng này có nhất quán trên mỗi thiết bị qua nhiều cài đặt của cùng một ứng dụng không?
samsam

4

@Grantland "Giải pháp khá sạch" này trông tương tự như cải tiến của riêng tôi đối với giải pháp iPhoneDeveloperTips.

Bạn có thể xem bước của tôi ở đây: 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;
}

và tôi không hiểu tại sao tôi có thể thêm nhận xét cho câu trả lời của riêng mình mà không cho câu trả lời của người khác? : /
Cœur

1
Bởi vì danh tiếng của bạn không đủ cao.
honus

Cảm ơn, có vẻ như một vài người đã đưa ra các biến thể của giải pháp này: ios.biomsoft.com/2011/11/07/determine-mac-address
josh-frag 25/213

1

Không thể thực hiện được nữa trên các thiết bị chạy iOS 7.0 trở lên, do đó không có sẵn địa chỉ MAC trong Swift.

Như Apple đã nêu:

Trong iOS 7 trở lên, nếu bạn hỏi địa chỉ MAC của thiết bị iOS, hệ thống sẽ trả về giá trị 02: 00: 00: 00: 00: 00. Nếu bạn cần xác định thiết bị, thay vào đó, hãy sử dụng thuộc tính định danhForVendor của UIDevice. (Các ứng dụng cần một mã định danh cho mục đích quảng cáo của riêng họ nên xem xét sử dụng thuộc tính AdvertisingIdentifier của 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

Để tạo uniqueString dựa trên số nhận dạng duy nhất của thiết bị trong iOS 6:

#import <AdSupport/ASIdentifierManager.h>

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

1
Làm thế nào điều này liên quan đến câu hỏi?
Valeriy Van

1
Địa chỉ Mac là cần thiết để xác định duy nhất thiết bị trong hầu hết các trường hợp. Thay vào đó, bạn có thể sử dụng giải pháp này.
Denis Kutlubaev

0

Rất nhiều câu hỏi này chỉ giải quyết địa chỉ Mac. Nếu bạn cũng yêu cầu địa chỉ IP tôi vừa viết này, có thể cần một số công việc nhưng dường như hoạt động tốt trên máy của tôi ...

- (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 @"?.?.?.?";
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.