Skip to content

Phone-native BLE/WiFi scanning for surveillance devices #94

@dougborg

Description

@dougborg

Idea

Use the phone's own BLE and WiFi radios to passively scan for nearby surveillance devices — no FlockSquawk, flock-you, or other external hardware required. A "wardriving lite" approach that works with just the phone.

This issue is a proposal/placeholder to gather community feedback, ideas, and suggestions — not a prescriptive spec.

Why

Not everyone has (or wants) dedicated scanning hardware. Most phones have BLE and WiFi radios that can detect nearby devices. While less powerful than a dedicated scanner with monitor mode, phone-native scanning can still catch cameras that advertise via BLE or broadcast recognizable WiFi SSIDs — especially during setup or when running access points for mobile viewing.

How it might work

  • BLE scan: Use flutter_blue_plus (already a dependency from PR Add FlockSquawk scanner integration (USB + BLE) #37) to scan for BLE advertisements matching known camera patterns (e.g., FS Ext Battery for Flock Safety)
  • WiFi scan: Use platform-specific APIs to enumerate nearby WiFi networks, filter through OUI watchlist + SSID database
  • Results feed into the same RfDetection pipeline and rf_devices/rf_sightings tables
  • Could run as a passive background scan during normal app use, or as an explicit "scan now" action

Platform Considerations

iOS

  • BLE scanning works well via CoreBluetooth
  • WiFi scanning is severely limited — no public API to enumerate nearby networks without a special Apple entitlement (NEHotspotHelper). This likely means WiFi scanning would be BLE-only on iOS.

Android

  • BLE scanning works well
  • WiFi scanning is available but throttled — Android 9+ limits scans to 4 per 2 minutes in the foreground
  • Background scanning is even more restricted

Battery

  • Continuous scanning drains the battery significantly
  • Need configurable scan intervals and/or smart triggers (e.g., only scan when moving, only scan in certain areas)

Considerations

  • This is a substantial feature — could be its own PR/milestone
  • The scanner architecture from PR Add FlockSquawk scanner integration (USB + BLE) #37 was designed to be extensible — phone-native scanning would be a new ScannerService implementation
  • Need clear UX to distinguish "phone-detected" vs "hardware-detected" vs "Wigle-sourced" devices
  • Should work alongside hardware scanners, not replace them

Open Questions

  • Is BLE-only scanning (without WiFi) useful enough on iOS to be worth implementing?
  • What should the default scan behavior be — always-on background, manual trigger, or somewhere in between?
  • How to handle the Android WiFi scan throttle — queue scans, show a cooldown timer?
  • Should this integrate with the existing scanner screen or have its own UI?

Effort Estimate

Medium

Dependencies

Related


Technical Research

Deep feasibility analysis of phone-native BLE/WiFi scanning — what APIs exist, what data we can actually get, platform constraints, and how scanning interacts with real-world radio usage (CarPlay, Android Auto, Bluetooth audio, etc.).

Platform Capability Matrix

Capability Android iOS
BLE scan — get device names Yes Yes
BLE scan — get MAC address Yes No (random UUID only)
BLE scan — get manufacturer data Yes Yes
BLE scan — passive (no connect) Yes Yes
BLE scan — background Yes (foreground service) Yes but throttled (>15s intervals)
WiFi scan — enumerate nearby APs Yes (throttled) No (no API exists)
WiFi scan — get BSSID/MAC Yes No (current network only)
WiFi scan — get SSID Yes Current network only
WiFi scan — background Yes (foreground service) No

Bottom line: BLE scanning is viable cross-platform (with iOS limitations on MAC addresses). WiFi scanning is Android-only — iOS has no API to enumerate nearby networks at all.

BLE Scanning — The Strong Path

flutter_blue_plus (already a dependency in PR #37) provides passive BLE advertisement scanning. From each advertisement we can extract:

  • Device name (advertised local name) — matches patterns like FS Ext Battery, IPCAM-*, etc.
  • Manufacturer-specific dataMap<int, Uint8List> keyed by Company Identifier Code (the BLE equivalent of OUI)
  • Service UUIDs — can identify specific device types (e.g., Raven acoustic detectors use custom UUIDs)
  • RSSI — signal strength for distance estimation
  • TX Power Level — for more accurate distance calculation

All available without connecting to the device — pure passive scanning of advertisement packets.

Android BLE

  • Full MAC address available → direct OUI matching possible
  • Can filter scans by MAC, name, service UUID
  • No scan duration limits in foreground
  • Background: requires foreground service with persistent notification

iOS BLE

  • MAC address NOT available — Apple replaces it with a randomly rotating UUID
  • Must rely on: device name, manufacturer data bytes, service UUIDs
  • Background scanning works but is discontinuous — iOS controls the interval (can be >15 seconds)
  • Multiple discoveries of same peripheral are coalesced into a single event in background
  • Must declare bluetooth-central background mode (PR Add FlockSquawk scanner integration (USB + BLE) #37 already does this)

What We Can Detect via BLE

Device Type Detection Method Confidence
Flock Safety cameras BLE name FS Ext Battery High
Flock Safety (by OUI) Manufacturer data / MAC prefix (Android only) High
Raven gunshot detectors Custom BLE service UUID High
Ring doorbells BLE name during setup mode Medium (only during setup)
Generic BLE cameras Name patterns (camera-*, IPCAM-*) Medium
Cameras with BLE beacons Manufacturer data matching Varies

Key limitation: Most surveillance cameras (Hikvision, Dahua, Axis, etc.) are WiFi-only — they don't advertise via BLE. BLE scanning primarily catches: Flock Safety, Raven, and consumer devices during setup/pairing modes.

BLE Battery Impact

  • Foreground continuous scanning: ~1-3% additional battery per hour
  • Background (iOS throttled): negligible (<5% per 24 hours)
  • BLE 5.x (modern phones): significantly more efficient than BLE 4.x

WiFi Scanning — Android Only, With Constraints

Android: WifiManager.startScan()

Available data per network:

  • BSSID (full MAC address) → OUI matching possible
  • SSID (network name) → pattern matching
  • RSSI (signal strength)
  • Frequency / channel
  • Capabilities (security type)
  • Timestamp

Throttling (since Android 9):

  • 4 scans per 2-minute window — hard limit, cannot be bypassed
  • WifiManager.startScan() silently fails if throttled (returns cached results)

Permissions:

  • Android 13+: NEARBY_WIFI_DEVICES (can declare neverForLocation flag)
  • Android 12 and below: ACCESS_FINE_LOCATION
  • Background: additionally requires ACCESS_BACKGROUND_LOCATION + foreground service

Flutter package: wifi_scan on pub.dev — Android-only, actively maintained

iOS: No Nearby Network Scanning

Apple provides NO API to enumerate nearby WiFi networks. What iOS does offer:

  • NEHotspotNetwork.fetchCurrent() — returns SSID + BSSID of the currently connected network only
  • Requires com.apple.developer.networking.wifi-info entitlement
  • NEHotspotHelper exists but requires a special Apple-granted entitlement (meant for captive portal/hotspot providers, not general scanning)
  • There is no workaround. On iOS, we cannot see any WiFi network the user isn't connected to.

What We Can Detect via WiFi (Android Only)

Device Type Detection Method Confidence
Hikvision cameras OUI prefix from BSSID High
Dahua / Amcrest cameras OUI prefix from BSSID High
Flock Safety cameras OUI prefix from BSSID High
Ring / Nest / Wyze / Arlo OUI prefix from BSSID Medium-High
Dahua NVRs SSID pattern NVR2.4G High
Generic IP cameras SSID patterns IPCAM-*, camera-* Medium

WiFi scanning is the more powerful detection method — most surveillance cameras have WiFi but not BLE. But it's Android-only.

WiFi Battery Impact

  • Minimal — WiFi scanning draws <1mW additional over the already-active WiFi radio
  • 4 scans per 2 minutes = negligible drain

Radio Conflicts — Scanning While Driving

A typical scenario: phone mounted in car, connected to car audio via Bluetooth, possibly running Android Auto or CarPlay, DeFlock scanning.

Scenario BLE Scan WiFi Scan (Android) Notes
Phone only (no car) Full Full (4/2min throttle) Best case
+ Classic BT audio Full Full No conflict — different protocol stacks
+ Wired Android Auto Full Full USB = no radio conflict
+ Wired CarPlay Full N/A (iOS) USB = no radio conflict
+ Wireless Android Auto Full Degraded WiFi Direct on 5GHz conflicts
+ Wireless CarPlay Throttled N/A (iOS) Both degraded on iOS
+ FlockSquawk on BLE Interleaved Full Can't scan + GATT connect simultaneously
+ FlockSquawk on USB Full Full BLE freed for scanning

Key takeaways:

  • Classic Bluetooth audio (A2DP/HFP) has no conflict with BLE scanning — different protocol stacks on dual-mode chip
  • Wired car connections are the best scenario — USB for data, all radios free
  • Wireless Android Auto (5GHz WiFi Direct) degrades WiFi scanning
  • Wireless CarPlay (2.4GHz WiFi Direct) plus iOS throttling = severely limited scanning
  • FlockSquawk on BLE conflicts with BLE advertisement scanning (flutter_blue_plus recommends stopping scans before connecting)

Practical Architecture

Scanning Modes

  1. Active Scan (foreground, user-initiated): Full BLE + WiFi scan. Real-time results. Highest power, highest detection.
  2. Passive Background Scan: BLE-only, opportunistic. Runs while app is in use for other things. Low power, catches BLE-advertising devices. On iOS, system-throttled.
  3. Wardriving Mode: Continuous active scanning with GPS correlation. Foreground service (Android) with persistent notification. Designed for dedicated mapping sessions.

Service Architecture

ScannerService (abstract)
├── BleScannerService      ← FlockSquawk BLE GATT connection
├── UsbScannerService      ← FlockSquawk USB serial
└── PhoneNativeScannerService  ← NEW: phone's own radios
    ├── Uses flutter_blue_plus for BLE advertisement scanning
    ├── Uses wifi_scan (Android) for WiFi AP enumeration
    ├── Filters through OUI/SSID watchlist (#91)
    └── Emits RfDetection events into same pipeline

Key difference: FlockSquawk services receive pre-classified detections. PhoneNativeScannerService must do its own matching against the watchlist.

Certainty Scoring

Phone-native detections are inherently less certain than dedicated hardware:

Match Type Suggested Certainty Alert Level
OUI match only (WiFi BSSID) 15-25 1 (Info)
OUI + suspicious SSID pattern 40-55 2 (Suspicious)
Known camera SSID exact match 55-70 2 (Suspicious)
Known BLE name exact match 55-70 2 (Suspicious)
Multiple signal matches (OUI + SSID + repeated sighting) 70-85 3 (Confirmed)

Memory & Performance

Wardriving with active BLE scanning can discover hundreds/thousands of devices:

  • Only retain devices matching the watchlist — discard non-matching advertisements immediately
  • Deduplicate: update existing records, not create new ones
  • Batch SQLite writes during high-frequency sighting periods

Permissions UX

Android — New Permissions Needed

  • NEARBY_WIFI_DEVICES (Android 13+) — for WiFi scanning
  • ACCESS_FINE_LOCATION (Android <13) — for WiFi scanning
  • ACCESS_BACKGROUND_LOCATION (Android 10+) — only for background/wardriving mode

iOS — Mostly Already Declared

User-facing explanation: "DeFlock uses Bluetooth and WiFi scanning to detect nearby surveillance devices. No personal data is collected. All scanning happens on your device."

iOS-Specific Strategy

What works on iOS:

  • BLE device name matching (catches Flock Safety FS Ext Battery, setup-mode consumer cameras)
  • BLE manufacturer data matching (Company Identifier Codes)
  • BLE service UUID matching (catches Raven detectors)
  • Current WiFi network check (if connected to a camera's AP — unlikely but free to check)

What doesn't work on iOS:

  • WiFi nearby network enumeration (no API)
  • BLE MAC-based OUI matching (MACs are randomized)
  • Background continuous scanning (system throttles to >15s intervals)

Honest assessment: iOS phone-native scanning is significantly less useful than Android. It primarily catches BLE-advertising devices (Flock Safety, Raven, cameras in setup mode). It won't catch the majority of surveillance cameras that only have WiFi. This should be clearly communicated to iOS users. Still worth building — BLE-only scanning on iOS catches Flock Safety devices without hardware, and combined with Wigle data (#92) or wardriving imports (#93), users get coverage from other sources.

Recommended Phasing

  1. First: Android BLE + WiFi scanning — most capable platform, covers the most devices. Depends on Curated surveillance device OUI + SSID watchlist #91 (watchlist).
  2. Second: iOS BLE scanning — limited but still catches Flock Safety and setup-mode devices. Low incremental effort if Android is done first.
  3. Third: Background/wardriving mode — foreground service (Android), background BLE mode (iOS). Higher complexity, handle radio conflicts gracefully.
  4. Defer: Car integration conflict handling — detect CarPlay/Android Auto state and adjust. Nice to have but not blocking.

Updated Open Questions

Based on this research, the open questions above are refined:

  1. Is iOS BLE-only scanning useful enough to ship? Research says yes — it catches Flock Safety without hardware, and the incremental effort after Android is small. But expectations should be managed.

  2. Should phone-native scanning coexist with FlockSquawk, or be mutually exclusive? The BLE radio conflict means we can't scan BLE advertisements while maintaining a BLE GATT connection to FlockSquawk. Options:

  3. Background scanning scope: Should phone-native scanning run in background by default, or only when user explicitly enables it? Battery vs detection trade-off. Research suggests: opt-in for background, always available as foreground "scan now."

  4. Wardriving mode as separate feature? A dedicated "wardriving mode" with continuous scanning + GPS logging could be a distinct UX from opportunistic background scanning.

  5. Interaction with Android Auto / CarPlay support #72 (Android Auto / CarPlay): Should the app detect when Android Auto / CarPlay is active and automatically adjust scanning behavior (e.g., disable WiFi scanning during wireless Android Auto)? See radio conflict matrix above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions