Minimize Bluetooth Interaction

ID

swift.minimize_bluetooth

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Efficiency

Language

Swift

Tags

battery, ble, efficiency

Description

Reports CBCentralManager.scanForPeripherals(withServices:options:) called with CBCentralManagerScanOptionAllowDuplicatesKey: true. With that key on, Core Bluetooth delivers every advertising packet from every nearby peripheral, keeping the BLE radio in a high duty cycle and draining the battery in seconds.

central.scanForPeripherals(
    withServices: [serviceUUID],
    options: [CBCentralManagerScanOptionAllowDuplicatesKey: true]   // FLAW
)

Rationale

The default scan behaviour coalesces consecutive advertisements from the same peripheral and reports it once. Allowing duplicates is meant only for short presence-tracking sessions where each ad packet carries meaningful data (iBeacon dwell, fitness sensor cadence) — the developer must opt in deliberately and stop the scan as soon as the data is collected.

Remediation

Drop the key, or set it to false for the common case:

central.scanForPeripherals(
    withServices: [serviceUUID],
    options: nil
)

central.scanForPeripherals(
    withServices: [serviceUUID],
    options: [CBCentralManagerScanOptionAllowDuplicatesKey: false]
)

When duplicates really are needed (presence tracking, RSSI sampling), keep the scan window short and stop it from the central’s queue as soon as the use case is satisfied.

When not to fire

The rule only inspects options dictionaries that are literal at the call site. Options built dynamically (var opts: [String: Any] = …​) are out of scope because tracking them requires flow analysis.