WWDC Quick Look 💓 By SwiftGGTeam
Find your accessory with Bluetooth Channel Sounding

Find your accessory with Bluetooth Channel Sounding

Watch original video

Highlight

In iOS 27, Apple brings Channel Sounding to Bluetooth accessories, enabling accessories to report precise distance and direction through Nearby Interaction and Core Bluetooth APIs.

Core Content

Finding accessories used to be awkward.

After a Bluetooth accessory connects, you know it is nearby, but not exactly where it is. Is it in the couch cushion? In the next room? Users can only guess from clues like “why won’t it connect?”

There has always been a possible approach: estimate distance from signal strength, or RSSI. But RSSI is too sensitive to the environment. A wall, a different device angle, or a nearby microwave can make the reading jump. RSSI also gives no direction at all.

Apple’s solution is Bluetooth Channel Sounding. This technology, introduced in the Bluetooth 5.1 standard, lets two devices calculate precise distance through two-way ranging, with accuracy down to the centimeter level.

iOS 27 opens this capability to developers:

  • Core Bluetooth adds APIs that can perform channel sounding directly with accessories and obtain distance data.
  • Nearby Interaction now supports Bluetooth channel sounding and can obtain both distance and direction.
  • Accessories need firmware updates to support it, and Apple provides complete implementation guidance for the accessory side.

With these pieces in place, finding an accessory becomes much simpler: open the app, see exactly where the accessory is on a map, how far away it is, and which direction to walk.

Details

Core Bluetooth channel sounding

([03:43](https://developer.apple.com/videos/play/wwdc2026/369/?time=223))

Core Bluetooth adds channel sounding support in iOS 27. First check whether the device supports it:

import CoreBluetooth

func isChannelSoundingSupported() -> Bool {
    guard centralManager.state == .poweredOn else { return false }
    if #available(iOS 27.0, *) {
        // Check whether the current device supports Bluetooth channel sounding
        return CBCentralManager.supportsFeatures(.channelSounding)
    }
    return false
}

Key points:

  • The device must be in the .poweredOn state.
  • supportsFeatures(.channelSounding) must return true.

Start a ranging session:

func startChannelSounding(_ peripheral: CBPeripheral) {
    guard peripheral.isConnected else { return }
    if #available(iOS 27.0, *) {
        // Step 1: Create the session configuration and specify this device as the initiator
        let config = CBChannelSoundingSessionConfiguration(role: .initiator)

        // Step 2: Start the channel sounding session
        peripheral.startChannelSoundingSession(config)
    }
}

Key points:

  • role: .initiator means the phone starts the ranging session and the accessory responds.
  • Only a connected peripheral can start ranging.
  • The accessory must support channel sounding.

Receive ranging results:

([04:09](https://developer.apple.com/videos/play/wwdc2026/369/?time=249))

func peripheral(_ peripheral: CBPeripheral,
                didReceive results: CBChannelSoundingProcedureResults?,
                error: Error?) {
    guard let results = results else { return }

    let distance = results.distance
    // Use the distance data
}

Key points:

  • distance returns a precise distance value, usually in centimeters.
  • Results arrive through a CBPeripheralDelegate callback.
  • Handle error cases.

Cancel the session:

func cancelChannelSounding(_ peripheral: CBPeripheral) {
    guard peripheral.isConnected else { return }
    if #available(iOS 27.0, *) {
        peripheral.cancelChannelSoundingSession(config)
    }
}

func peripheral(_ peripheral: CBPeripheral,
                didCompleteChannelSoundingSession error: Error?) {
    // The session has ended
}

Key points:

  • Both active cancellation and accessory disconnection trigger the completion callback.
  • Save power by stopping the session as soon as it is no longer needed.

Nearby Interaction integration

([04:41](https://developer.apple.com/videos/play/wwdc2026/369/?time=281))

Nearby Interaction can now use Bluetooth channel sounding as well, and it can provide direction information.

First check device capabilities:

import NearbyInteraction

func startChannelSoundingThroughNearbyInteraction(_ peripheral: CBPeripheral) {
    if #available(iOS 27.0, *) {
        // Step 1: Check whether the device supports Bluetooth channel sounding
        guard NISession.deviceCapabilities.supportsBluetoothChannelSounding else { return }

        // Step 2: Create the accessory configuration
        let config = NINearbyAccessoryConfiguration(
            bluetoothChannelSoundingIdentifier: peripheral.identifier,
            previousChannelSoundingIdentifier: nil)

        // Step 3: Enable camera assistance to support direction
        if NISession.deviceCapabilities.supportsCameraAssistance {
            config.isCameraAssistanceEnabled = true
        }
    }
}

Key points:

  • bluetoothChannelSoundingIdentifier uses the accessory’s UUID.
  • previousChannelSoundingIdentifier can reuse the previous session to speed up connection.
  • Enabling camera assistance provides direction data and requires user authorization.

Run the session:

([05:19](https://developer.apple.com/videos/play/wwdc2026/369/?time=319))

func runChannelSoundingThroughNearbyInteraction(_ config: NINearbyAccessoryConfiguration) {
    let session = NISession()
    session.delegate = self
    session.run(config)
}

Receive updates:

func session(_ session: NISession, didUpdate nearbyObjects: [NINearbyObjects]) {
    guard let object = nearbyObjects.first else { return }

    if let distance = object.distance {
        // Use the distance data
    }

    if let direction = object.horizontalAngle {
        // Use the direction data
    }
}

Key points:

  • distance is the precise distance.
  • horizontalAngle gives the horizontal direction angle.
  • Data updates continuously, enabling real-time tracking.

Optimize direction output:

func updateAccessoryMotionState(_ isMoving: Bool) {
    let motionState = isMoving ? .moving : .stationary
    session.updateMotionState(motionState, forObjectWithToken: object.discoveryToken)
}

Key points:

  • Tell Nearby Interaction whether the accessory is stationary or moving.
  • Direction calculations are more accurate when the accessory is stationary.
  • If the accessory has motion sensors, pass the live state.

Power optimization

Channel sounding consumes power, so Apple recommends using it on demand:

  • Start sessions only when needed.
  • Cancel as soon as enough data has been collected.
  • Avoid continuous ranging in the background.
  • Adjust update frequency based on the use case.

Accessory-side requirements

Accessories need firmware updates to support channel sounding:

  • Implement Bluetooth 5.1 or later.
  • Support the Channel Sounding feature.
  • Act as the responder in the accessory role.
  • Follow Apple’s accessory implementation guide.

Key Takeaways

  1. Precise item-finding app: Go beyond “nearby” to “30 centimeters to the left of the couch.” Give keys, wallets, or earbuds precise positioning so users can walk straight to them.

  2. Smart accessory triggers: Automatically trigger features when a user reaches a certain distance from an accessory, such as turning on a light when nearby or showing an unlock prompt near a door lock.

  3. Indoor navigation assistance: In malls or airports, use the distance and direction of nearby fixed Bluetooth beacons for rough indoor positioning that helps users find stores or gates.

  4. Game accessory positioning: Track the exact position of motion-game accessories so the game knows where a player’s controller is, how far it is from the screen, and which direction it faces.

  5. AR accessory visualization: Combine camera assistance with positioning so users can “see” hidden accessories in an AR view, such as glasses that fell into a couch gap and are marked directly on screen.

Comments

GitHub Issues · utterances