Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get CellID, MCC, MNC, LAC, and Network in iOS 5.1

I need to retrieve CellID, MCC, MNC, LAC and Network (GSM, 3G) of the current Serving Cell Tower in iOS 5.1 (iPhone 4S). I know this information is available because I can see it in FieldTest Mode (accessible after calling ****3001#12345#****). I suppose it to be accessible via Private/Undocumented iOS Frameworks.

In the question iphone, check values of cellId / Lac the author indicates I can get radio Informations cellId, Lac, MNC, MCC on iOS, but no information on how to do this is provided.

Can anybody tell me how to get this info?

like image 672
poorDeveloper Avatar asked Nov 15 '12 14:11

poorDeveloper


People also ask

What is cell ID MCC MNC LAC?

Cell Global Identity (CGI) is a globally unique identifier for a Base Transceiver Station in mobile phone networks. It consists of four parts: Mobile Country Code (MCC), Mobile Network Code (MNC), Location Area Code (LAC) and Cell Identification (CI).

How do I find the cell ID for my iPhone?

*3001#12345#* and tap Call. Enter Field Mode. Field mode reveals many of the inner settings of your iPhone, specifically up-to-date network and cell information.


2 Answers

I know three ways on how you can do it on iOS 5.x - 7.x. All of them use private APIs from CoreTelephony.framework. Supports both GSM and UMTS.

1) Using cell monitor

struct CTResult
{
    int flag;
    int a;
};

extern CFStringRef const kCTCellMonitorCellType;
extern CFStringRef const kCTCellMonitorCellTypeServing;
extern CFStringRef const kCTCellMonitorCellTypeNeighbor;
extern CFStringRef const kCTCellMonitorCellId;
extern CFStringRef const kCTCellMonitorLAC;
extern CFStringRef const kCTCellMonitorMCC;
extern CFStringRef const kCTCellMonitorMNC;
extern CFStringRef const kCTCellMonitorUpdateNotification;

id _CTServerConnectionCreate(CFAllocatorRef, void*, int*);
void _CTServerConnectionAddToRunLoop(id, CFRunLoopRef, CFStringRef);

#ifdef __LP64__

void _CTServerConnectionRegisterForNotification(id, CFStringRef);
void _CTServerConnectionCellMonitorStart(id);
void _CTServerConnectionCellMonitorStop(id);
void _CTServerConnectionCellMonitorCopyCellInfo(id, void*, CFArrayRef*);

#else

void _CTServerConnectionRegisterForNotification(struct CTResult*, id, CFStringRef);
#define _CTServerConnectionRegisterForNotification(connection, notification) { struct CTResult res; _CTServerConnectionRegisterForNotification(&res, connection, notification); }

void _CTServerConnectionCellMonitorStart(struct CTResult*, id);
#define _CTServerConnectionCellMonitorStart(connection) { struct CTResult res; _CTServerConnectionCellMonitorStart(&res, connection); }

void _CTServerConnectionCellMonitorStop(struct CTResult*, id);
#define _CTServerConnectionCellMonitorStop(connection) { struct CTResult res; _CTServerConnectionCellMonitorStop(&res, connection); }

void _CTServerConnectionCellMonitorCopyCellInfo(struct CTResult*, id, void*, CFArrayRef*);
#define _CTServerConnectionCellMonitorCopyCellInfo(connection, tmp, cells) { struct CTResult res; _CTServerConnectionCellMonitorCopyCellInfo(&res, connection, tmp, cells); }

#endif

...

id CTConnection = _CTServerConnectionCreate(NULL, CellMonitorCallback, NULL);
_CTServerConnectionAddToRunLoop(CTConnection, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
_CTServerConnectionRegisterForNotification(CTConnection, kCTCellMonitorUpdateNotification);
_CTServerConnectionCellMonitorStart(CTConnection);

int CellMonitorCallback(id connection, CFStringRef string, CFDictionaryRef dictionary, void *data)
{
    int tmp = 0;
    CFArrayRef cells = NULL;
    _CTServerConnectionCellMonitorCopyCellInfo(connection, (void*)&tmp, &cells);
    if (cells == NULL)
    {
        return 0;
    }

    for (NSDictionary* cell in (NSArray*)cells)
    {
        int LAC, CID, MCC, MNC;

        if ([cell[(NSString*)kCTCellMonitorCellType] isEqualToString:(NSString*)kCTCellMonitorCellTypeServing])
        {
            LAC = [cell[(NSString*)kCTCellMonitorLAC] intValue];
            CID = [cell[(NSString*)kCTCellMonitorCellId] intValue];
            MCC = [cell[(NSString*)kCTCellMonitorMCC] intValue];
            MNC = [cell[(NSString*)kCTCellMonitorMNC] intValue];
        }
        else if ([cell[(NSString*)kCTCellMonitorCellType] isEqualToString:(NSString*)kCTCellMonitorCellTypeNeighbor])
        {
        }
    }

    CFRelease(cells);

    return 0;
}

2) Using CTTelephonyCenter

kCTRegistrationCellChangedNotification is sent every time current serving cell tower is changed.

extern CFStringRef const kCTRegistrationCellChangedNotification;
extern CFStringRef const kCTRegistrationGsmLac;
extern CFStringRef const kCTRegistrationLac;
extern CFStringRef const kCTRegistrationGsmCellId;
extern CFStringRef const kCTRegistrationCellId;

CFStringRef CTSIMSupportCopyMobileSubscriberCountryCode(CFAllocatorRef);
CFStringRef CTSIMSupportCopyMobileSubscriberNetworkCode(CFAllocatorRef);

id CTTelephonyCenterGetDefault();
void CTTelephonyCenterAddObserver(id, void, CFNotificationCallback, CFStringRef, void, CFNotificationSuspensionBehavior);

...

CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault(), NULL, callback, NULL, NULL, CFNotificationSuspensionBehaviorHold);

void callback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
{
    NSString* notification = (NSString*)name;
    NSDictionary *cellInfo = (NSDictionary*)userInfo;

    if ([notification isEqualToString:(NSString*)kCTRegistrationCellChangedNotification])
    {
        int LAC, CID, MCC, MNC;

        if (cellInfo[(NSString*)kCTRegistrationGsmLac])
        {
            LAC = [cellInfo[(NSString*)kCTRegistrationGsmLac] intValue];
        }
        else if (data[(NSString*)kCTRegistrationLac])
        {
            LAC = [cellInfo[(NSString*)kCTRegistrationLac] intValue];
        }

        if (cellInfo[(NSString*)kCTRegistrationGsmCellId])
        {
            CID = [cellInfo[(NSString*)kCTRegistrationGsmCellId] intValue];
        }
        else if (cellInfo[(NSString*)kCTRegistrationCellId])
        {
            CID = [cellInfo[(NSString*)kCTRegistrationCellId] intValue];
        }

        MCC = [[(NSString*)CTSIMSupportCopyMobileSubscriberCountryCode(NULL) autorelease] intValue];
        MNC = [[(NSString*)CTSIMSupportCopyMobileSubscriberNetworkCode(NULL) autorelease] intValue];
    }
}

3) This returns current serving cell tower

struct CTResult
{
    int flag;
    int a;
};

id _CTServerConnectionCreate(CFAllocatorRef, void*, int*);

#ifdef __LP64__

void _CTServerConnectionGetLocationAreaCode(id, int*);
void _CTServerConnectionGetCellID(id, int*);

#else

void _CTServerConnectionGetLocationAreaCode(struct CTResult*, id, int*);
#define _CTServerConnectionGetLocationAreaCode(connection, LAC) { struct CTResult res; _CTServerConnectionGetLocationAreaCode(&res, connection, LAC); }

void _CTServerConnectionGetCellID(struct CTResult*, id, int*);
#define _CTServerConnectionGetCellID(connection, CID) { struct CTResult res; _CTServerConnectionGetCellID(&res, connection, CID); }

#endif

...

int CID, LAC, MCC, MNC;

id CTConnection = _CTServerConnectionCreate(NULL, NULL, NULL);
_CTServerConnectionGetCellID(CTConnection, &CID);
_CTServerConnectionGetLocationAreaCode(CTConnection, &LAC);
MCC = [[(NSString*)CTSIMSupportCopyMobileSubscriberCountryCode(NULL) autorelease] intValue];
MNC = [[(NSString*)CTSIMSupportCopyMobileSubscriberNetworkCode(NULL) autorelease] intValue];

UPDATE

On ARM64 (iPhone 5S) there is an issue with all CoreTelephony functions that accept struct CTResult argument. Apparently, 64-bit version of CoreTelephony exports these functions without struct CTResult argument. Because of that you will get an error on ARM64 if you call these functions like you did in the past - arguments will be wrong. I updated function declarations so that they work on both 32-bit and 64-bit ARM architectures. I tested it and it works on both iPhone 4S and iPhone 5S.

This only applies to ARM64. If you build your project for 32-bit ARM architecture then there is no such issue. Your application will use 32-bit version of CoreTelephony which expects struct CTResult argument.

8.3 UPDATE

As of iOS 8.3 all of the above solutions require entitlement to work

<key>com.apple.CommCenter.fine-grained</key>
<array>
    <string>spi</string>
</array>

Not only cell monitor is protected but it seems like all of the CoreTelephony notifications now require that entitlement to work. For example, kCTMessageReceivedNotification also affected.

like image 198
creker Avatar answered Oct 12 '22 12:10

creker


suscriberCellularProvider is an object method (vs class method).

You can take a look how to use it here: Determine iPhone user's country

I think CTCarrier has MCC and MNC.

You can check network type using the code from this question: How to check if iPhone supports CDMA or GSM

And look this question for CellID: CTServerConnectionGetCellID routine core telephony

like image 39
Victor Ronin Avatar answered Oct 12 '22 11:10

Victor Ronin