Привет!
Я хочу показать, как, не используя приватных API ( = не используя приватных фреймворков/классов/функций) можно собирать разнообразные данные о использовании устройства.
Вот описание информации, которую можно получить:
- Мощность сигнала сотовой сети: RSSI в дБм и относительную мощность в «палках»
- Качество сигнала WiFi (0 — плохо, 4 — хорошо)
- Состояние регистрации в сотовой сети: наличие SIM, поиск сети
- Тип сети передачи данных: 2G, 3G, WiFi
- Заряд аккумулятора с точностью до процента (стандартные средства дают точность в 5%)
- Включен ли «режим самолёта» («airplane mode»)
- Включены ли различные сервисы: будильник, Airplay, VPN, перенаправление звонков, Nike+
Собственно, суть метода:
typedef struct { BOOL itemIsEnabled[24]; char timeString[64]; int gsmSignalStrengthRaw; int gsmSignalStrengthBars; char serviceString[100]; char serviceCrossfadeString[100]; char serviceImages[2][100]; char operatorDirectory[1024]; unsigned serviceContentType; int wifiSignalStrengthRaw; int wifiSignalStrengthBars; unsigned dataNetworkType; int batteryCapacity; unsigned batteryState; char batteryDetailString[150]; int bluetoothBatteryCapacity; int thermalColor; unsigned thermalSunlightMode : 1; unsigned slowActivity : 1; unsigned syncActivity : 1; char activityDisplayId[256]; unsigned bluetoothConnected : 1; unsigned displayRawGSMSignal : 1; unsigned displayRawWifiSignal : 1; unsigned locationIconType : 1; } iOS6Data; // retrieve data void *app = (__bridge void *)([UIApplication sharedApplication]); ptrdiff_t providerOffset = 52; void *provider = *(void**)(app + providerOffset); ptrdiff_t iOS6DataOffset = 116; iOS6Data *data = (iOS6Data*)(provider + iOS6DataOffset);
Минимальная программа, демонстрирующая возможности подхода
enum { kTimeItem = 0, kLockItem, kAirplaneItem, kSignalStrengthItem, kServiceItem, kDataNetworkItem, kBatteryItem, kBatteryPercentItem, kNotChargingItem, kBluetoothBatteryItem, kBluetoothItem, kTTYItem, kAlarmItem, kPlusItem, kPlayItem, kLocationItem, kRotationLockItem, kDoubleHeightItem, kAirPlayItem, kVPNItem, kCallForwardItem, kActivityItem, kThermalColorItem }; typedef struct { BOOL itemIsEnabled[24]; char timeString[64]; int gsmSignalStrengthRaw; int gsmSignalStrengthBars; char serviceString[100]; char serviceCrossfadeString[100]; char serviceImages[2][100]; char operatorDirectory[1024]; unsigned serviceContentType; int wifiSignalStrengthRaw; int wifiSignalStrengthBars; unsigned dataNetworkType; int batteryCapacity; unsigned batteryState; char batteryDetailString[150]; int bluetoothBatteryCapacity; int thermalColor; unsigned thermalSunlightMode : 1; unsigned slowActivity : 1; unsigned syncActivity : 1; char activityDisplayId[256]; unsigned bluetoothConnected : 1; unsigned displayRawGSMSignal : 1; unsigned displayRawWifiSignal : 1; unsigned locationIconType : 1; } iOS6Data; void proof_of_concept() { // we need to check runtime before start NSString *systemVersion = [[UIDevice currentDevice] systemVersion] ; NSScanner *scanner = [NSScanner scannerWithString:systemVersion]; int runtime; [scanner scanInt:&runtime]; if (runtime != 6) { NSLog(@"К сожалению, программа работает только на iOS 6"); UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Не удалось получить данные" message:@"Для работы программы необходима iOS 6." delegate:nil cancelButtonTitle:@"Закрыть" otherButtonTitles:nil]; [alertView show]; return; } // retrieve data void *app = (__bridge void *)([UIApplication sharedApplication]); ptrdiff_t providerOffset = 52; void *provider = *(void**)(app + providerOffset); ptrdiff_t iOS6DataOffset = 116; iOS6Data *data = (iOS6Data*)(provider + iOS6DataOffset); // usage example NSMutableString *example = [NSMutableString stringWithCapacity:1000]; [example appendFormat: @"Сигнал сотовой сети: %d дБм\n", data->gsmSignalStrengthRaw ]; [example appendFormat: @"Заряд батареи: %@\n", @(data->batteryDetailString)]; switch (data->dataNetworkType) { case 2: [example appendString: @"Тип сети передачи данных: 2G\n"]; break; case 3: [example appendString: @"Тип сети передачи данных: 3G\n"]; break; case 5: [example appendString: @"Тип сети передачи данных: WiFi\n"]; default: break; } if (data->itemIsEnabled[kAlarmItem]) { [example appendString:@"Будильник включен"]; } if (data->itemIsEnabled[kCallForwardItem]) { [example appendString:@"Влючено перенаправление звонков"]; } if (data->itemIsEnabled[kAirplaneItem]) { [example appendString:@"Влючен \"Режим самолёта\""]; } NSLog(@"%@", example); UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Info" message:example delegate:nil cancelButtonTitle:@"Закрыть" otherButtonTitles: nil]; [alertView show]; }
Плюсы:
- Данные постоянно остаются актуальными, их обновлением занимается само приложение (UIApplication)
- Решение не использует приватные API
Минусы:
- Решение построено на рантайме iOS, поэтому структуры и константы отличаются для iOS 5, 6 и 7
- Полученная информация довольна поверхностна, нельзя например получить другие статистики сотовой сети
Если интересно, как это работает, откуда берутся константы и описания структур данных, пишите в комментариях, дополню статью.
ссылка на оригинал статьи http://habrahabr.ru/post/183650/
Добавить комментарий