J'ai besoin de récupérer CellID, MCC, MNC, LAC et le réseau (GSM, 3G) de l'actuel Serving Cell Tower sous iOS 5.1 (iPhone 4S). Je sais que cette information est disponible parce que je peux la voir en mode FieldTest (accessible après avoir appelé **** 3001 # 12345 # ****). Je suppose que cela doit être accessible via des cadres iOS privés/non documentés.
Dans la question iphone, vérifiez les valeurs de cellId/Lac l'auteur indique je peux obtenir des informations radio radio cellID, Lac, MNC, MCC sur iOS, mais aucune information sur la procédure à suivre n'est fournie.
Quelqu'un peut-il me dire comment obtenir cette information?
Je connais trois manières de procéder sur iOS 5.x - 7.x. Tous utilisent des API privées de CoreTelephony.framework. Prend en charge les réseaux GSM et UMTS.
1) Utilisation du moniteur de cellule
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) Utilisation de CTTelephonyCenter
kCTRegistrationCellChangedNotification
est envoyé chaque fois que la tour de cellules servant actuelle est modifiée.
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) Ceci retourne la tour de téléphonie cellulaire actuelle
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];
METTRE À JOUR
Sur ARM64 (iPhone 5S), toutes les fonctions CoreTelephony acceptant l’argument struct CTResult
posent un problème. Apparemment, la version 64 bits de CoreTelephony exporte ces fonctions sans l'argument struct CTResult
. A cause de cela, vous obtiendrez une erreur sur ARM64 si vous appelez ces fonctions comme par le passé - les arguments seront faux. J'ai mis à jour les déclarations de fonction afin qu'elles fonctionnent sur les architectures ARM 32 bits et 64 bits. Je l'ai testé et cela fonctionne à la fois sur iPhone 4S et iPhone 5S.
Ceci s'applique uniquement à ARM64. Si vous construisez votre projet pour une architecture 32 bits ARM, ce problème n'existe pas. Votre application utilisera la version 32 bits de CoreTelephony qui attend l'argument struct CTResult
.
8.3 MISE À JOUR
Depuis iOS 8.3, toutes les solutions ci-dessus nécessitent un droit au travail.
<key>com.Apple.CommCenter.fine-grained</key>
<array>
<string>spi</string>
</array>
Non seulement le moniteur de cellule est protégé, mais il semble que toutes les notifications CoreTelephony exigent désormais que ce droit fonctionne. Par exemple, kCTMessageReceivedNotification
est également affecté.
suscriberCellularProvider est une méthode objet (méthode vs classe).
Vous pouvez voir comment l'utiliser ici: Déterminer le pays de l'utilisateur de l'iPhone
Je pense que CTCarrier a MCC et MNC.
Vous pouvez vérifier le type de réseau en utilisant le code de cette question: Comment vérifier si un iPhone prend en charge les formats CDMA ou GSM
Et cherchez cette question pour CellID: CTServerConnectionGetCellID routine de téléphonie principale
Le code ci-dessous explique comment insérer le droit de travailler sur ios 8.3 . À partir de iOS 8.3, toutes les solutions ci-dessus requièrent un droit au travail.
<key>com.Apple.CommCenter.fine-grained</key>
<array>
<string>spi</string>
</array>
En effet, on dit que le code mentionné ci-dessus peut être exécuté pour obtenir le code lac et la cellule sur iOS 8.3 et versions ultérieures. Mais je ne sais vraiment pas comment insérer ce qui précède sur un téléphone jailbreaké. Quelqu'un pourrait-il donner des informations détaillées?.