Как я сделал сканер под iOS и Android для диагностики Wi-Fi-сети

Выбор инструментов и архитектура
Для кросс-платформенной разработки взял Flutter. Для сканирования Wi-Fi пришлось использовать два разныx пакета: flutter_wifi_scan для Android и wifi_info_plugin для iOS. Android даёт полный доступ к списку точек доступа с BSSID, SSID, уровнем сигнала и частотой. iOS же с iOS 9 ограничивает фоновое сканирование — приложение может получить информацию только о текущей сети. Пришлось добавить отдельный поток для периодического опроса и агрегации данных.
Архитектура модульная: отдельный слой для сбора данных (платформенные адаптеры), слой обработки (фильтрация, усреднение RSSI) и слой визуализации (графики на CustomPainter). Для хранения истории использовал SQLite через пакет sqflite.
Важное замечание: на Android нужно добавить разрешения ACCESS_FINE_LOCATION и ACCESS_WIFI_STATE, а на iOS — Capability Access WiFi Information. Без них сканирование не работает.
Сбор данных о сети на Android
На Android самый простой путь — использовать WifiManager через MethodChannel. Вот пример кода для запуска сканирования и получения результатов:
import 'package:flutter/services.dart';class AndroidWifiScanner { static const platform = MethodChannel('wifi_scanner'); FutureНа стороне Android (Kotlin) обрабатываем запрос:
override fun onMethodCall(call: MethodCall, result: Result) { if (call.method == "startScan") { val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val scanResults = wifiManager.scanResults val list = scanResults.map { scanResult -> mapOf( "ssid" to scanResult.SSID, "bssid" to scanResult.BSSID, "level" to scanResult.level, "frequency" to scanResult.frequency ) } result.success(list) context.unregisterReceiver(this) } } context.registerReceiver(receiver, IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) wifiManager.startScan() }}Сбор данных на iOS: ограничения и обход
iOS не даёт полного сканирования, но можно получить информацию о текущей точке доступа через NEHotspotNetwork. Для этого используем wifi_info_plugin:
import 'package:wifi_info_plugin/wifi_info_plugin.dart';class IosWifiScanner { Future<Map<String, dynamic>> getCurrentWifiInfo() async { try { var wifiInfo = await WifiInfoPlugin.wifiInfo; return { 'ssid': wifiInfo.ssid ?? '', 'bssid': wifiInfo.bssid ?? '', 'level': wifiInfo.level ?? 0, }; } catch (e) { print('Ошибка получения информации о Wi-Fi: $e'); return {}; } }}Чтобы хоть как-то оценить обстановку, пришлось добавить механизм перемещения пользователя и логирования уровня сигнала в разных точках. По сути, iOS-версия стала «следопытом», а Android — полноценным сканером.
Сравнение возможностей Android и iOS
| Параметр | Android | iOS |
|---|---|---|
| Доступ к списку точек доступа | Да (полный) | Нет (только текущая) |
| BSSID | Да | Да (для текущей) |
| Уровень сигнала (RSSI) | Да | Да (для текущей) |
| Частота/канал | Да | Нет |
| Фоновое сканирование | Да | Только в foreground |
| Разрешения | ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE | Access WiFi Information + Location |
Визуализация и анализ
Данные выводились в виде линии уровня сигнала по времени и карты точек доступа с цветовой индикацией (зелёный — сильный сигнал, красный — слабый). Для отрисовки графиков использовал CustomPainter. Также реализовал фильтр по SSID и сортировку по уровню сигнала. На Android можно было построить тепловую карту каналов — это позволило выявить перегруженный канал 6 в офисе.
Совет: для Android используйте метод getScanResults только после того, как сканирование завершилось. Иначе получите пустой список. Я повесил BroadcastReceiver на SCAN_RESULTS_AVAILABLE_ACTION.
Практические советы и результаты
- Для минимизации нагрузки на батарею делайте паузу между сканированиями не менее 10 секунд.
- На iOS не пытайтесь получить список сетей — только текущую. Смиритесь.
- Используйте SQLite для хранения истории — это позволяет увидеть динамику изменения сигнала.
- Добавьте экспорт данных в CSV, чтобы передать сисадмину.
Личное наблюдение автора: когда я запустил сканер на Android в офисе, сразу увидел, что на канале 6 работают 8 точек доступа — очевидная причина деградации. Перенос сети на канал 11 решил проблему. iOS-версия оказалась менее полезной, но её можно использовать для приёмочного тестирования зоны покрытия.
Заключение
Создать Wi-Fi сканер под обе платформы реально, но придётся учитывать ограничения iOS. Flutter позволил переиспользовать 80% кода, а платформенные адаптеры сделали остальное. Если нужно простое приложение для диагностики — берите готовые библиотеки, но если хотите глубже разобраться в сетевом стеке — пишите сами.
Источник: IT Фишки
