Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the MCC and MNC by means of CoreTelephony.framework private API in Objective-C

I need to obtain MCC and MNC code for the current country (NOT from the class CTCarrier for the SIM home country).

I use private API for CoreTelephony.framework. On the my device all works correct. But on the other devices in the method CellMonitorCallback we obtain cells = NULL.

May be somebody can help what I done wrong?


#import "AMCoreTelephone.h"
#import <CoreTelephony/CTCarrier.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>

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);
mach_port_t _CTServerConnectionGetPort(id);

#ifdef __LP64__
void _CTServerConnectionRegisterCallService(id);
void _CTServerConnectionUnregisterCallService(id,int*);
void _CTServerConnectionRegisterForNotification(id, CFStringRef);
void _CTServerConnectionCellMonitorStart(id);
void _CTServerConnectionCellMonitorStop(id);
void _CTServerConnectionCellMonitorCopyCellInfo(id, void*, CFArrayRef*);
void _CTServerConnectionIsInHomeCountry(id, void*, int*);
void _CTServerConnectionCopyCountryCode(id, void*, CFStringRef);

#else

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

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

void _CTServerConnectionIsInHomeCountry(struct CTResult*, id, int*);
#define CTServerConnectionIsInHomeCountry(connection, isHomeCountry) { struct CTResult res; _CTServerConnectionIsInHomeCountry(&res, connection, &isHomeCountry); }

#endif


@implementation AMCoreTelephone
{
    CTCarrier *_carrier;
    id CTConnection;
    mach_port_t  port;
}

+ (instancetype) sharedInstance
{
    static AMCoreTelephone *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[AMCoreTelephone alloc] init_true];
    });
    return instance;
}

- (instancetype) init_true
{
    if (self = [super init]) {
        _carrier = [[CTTelephonyNetworkInfo new] subscriberCellularProvider];
    }
    return self;
}


- (void) startMonitoring{
    #if TARGET_IPHONE_SIMULATOR
        return;
    #else
        CTConnection = _CTServerConnectionCreate(kCFAllocatorDefault, CellMonitorCallback, NULL);
        _CTServerConnectionRegisterForNotification(CTConnection, kCTCellMonitorUpdateNotification);

        port  = _CTServerConnectionGetPort(CTConnection);
        CFMachPortRef ref = CFMachPortCreateWithPort(kCFAllocatorDefault,port,NULL,NULL, NULL);
        CFRunLoopSourceRef rlref = CFMachPortCreateRunLoopSource ( kCFAllocatorDefault, ref, 0);
        CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent();
        CFRunLoopAddSource(currentRunLoop, rlref, kCFRunLoopCommonModes);

        _CTServerConnectionCellMonitorStart(CTConnection);

    #endif

}

- (void) stopMonitoring{
    _CTServerConnectionCellMonitorStop(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 (__bridge NSArray*)cells)
    {
        int LAC, CID, MCC, MNC;

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

    CFRelease(cells);

    return 0;
}

@end  
like image 464
Ryhor Avatar asked Nov 09 '22 14:11

Ryhor


1 Answers

I think the problem is using private api, so you can't run your app on non jailbreak phones. I'm researching the thing as same you but a little late :) and I found this answer to work on iOS 8.3, it says

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>

Also this project on github is only sample code for me that I can find.

I think you already know answer but this may helps someone else, because it's hard to find :)

like image 92
Gürhan KODALAK Avatar answered Nov 14 '22 23:11

Gürhan KODALAK