CtrlK
BlogDocsLog inGet started
Tessl Logo

thiennc-tesoglobal/ios-skills

Community-maintained Agent Skills for complete Swift and Apple-platform app delivery.

72

Quality

90%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Medium

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

SKILL.mdskills/core-bluetooth/

name:
core-bluetooth
description:
Build direct Bluetooth Low Energy central or peripheral workflows with Core Bluetooth, including GATT discovery, state restoration, MTU sizing, and background modes. Use for BLE scanning, peripheral connection, characteristic reads/writes/notifications, or peripheral advertisement.

Core Bluetooth

Implement Bluetooth Low Energy (BLE) communication on iOS using CBCentralManager (connecting to accessories) and CBPeripheralManager (advertising as an accessory). Targets Swift 6.3 / iOS 26+.

Contents

  • Permissions and Background Modes
  • Central vs Peripheral Roles
  • Core Communication Contract
  • State Restoration and MTU
  • Route by Task
  • Common Mistakes
  • Review Checklist
  • References

Permissions and Background Modes

Declare NSBluetoothAlwaysUsageDescription in Info.plist. For background execution, enable capabilities in Signing & Capabilities > Background Modes:

  • Uses Bluetooth LE accessories: Central role in background (bluetooth-central)
  • Acts as a Bluetooth LE accessory: Peripheral role in background (bluetooth-peripheral)
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app requires Bluetooth to connect to external fitness sensors.</string>
<key>UIBackgroundModes</key>
<array>
    <string>bluetooth-central</string>
</array>

Central vs Peripheral Roles

FeatureCentral (CBCentralManager)Peripheral (CBPeripheralManager)
Primary TaskScans, connects, and consumes GATT servicesPublishes services, advertises, responds to requests
DiscoveryscanForPeripherals(withServices:options:)startAdvertising(_:)
Data Read/WritereadValue(for:) / writeValue(_:for:type:)respond(to:withResult:)
UpdatesSubscribes with setNotifyValue(true, for:)updateValue(_:for:onSubscribedCentrals:)
QueueDedicated serial DispatchQueueDedicated serial DispatchQueue

Core Communication Contract

  1. Wait for .poweredOn: Never call scan, connect, or advertise until centralManagerDidUpdateState(_:) reports .poweredOn.
  2. Retain discovered peripherals: You must store a strong reference to CBPeripheral instances returned in didDiscover. If released, connection drops immediately.
  3. Scan with service UUIDs: In background mode, scanning without explicit CBUUID filters is disabled by iOS to preserve battery.
  4. Discover narrowly: Pass specific [CBUUID] arrays to discoverServices and discoverCharacteristics rather than nil to avoid slow full-GATT enumeration.
  5. Honor write types: Use .withResponse for acknowledged writes (peripheral(_:didWriteValueFor:error:)); use .withoutResponse only when canSendWriteWithoutResponse is verified.

State Restoration and MTU

  • State Restoration: Pass CBCentralManagerOptionRestoreIdentifierKey during manager initialization to allow iOS to relaunch the app in the background when a Bluetooth event occurs. Handle restoration in centralManager(_:willRestoreState:).
  • MTU & Packet Sizing: Check peripheral.maximumWriteValueLength(for:) before sending large payloads. The default BLE MTU is 23 bytes (20 payload bytes). Do not assume 512-byte MTU without checking.

Route by Task

  • For a complete SwiftUI-ready @Observable BLE manager, read SwiftUI BLE Integration.
  • For exponential backoff and automatic peripheral reconnection, read Reconnection Strategies.
  • For byte buffers and binary data parsing helpers, read Data Parsing Helpers.
  • For congestion control and packet flow management, read Write Flow Control.
  • For managing multiple simultaneous peripherals, read Multiple Peripheral Management.
  • For high-speed raw streaming without GATT overhead, read L2CAP Channels.
  • For peripheral role request handling and subscription updates, read Peripheral Role: Responding to Requests.

Common Mistakes

  • Initiating Bluetooth scanning before centralManagerDidUpdateState(_:) transitions to .poweredOn.
  • Failing to retain the CBPeripheral reference during connection, leading to silent drops.
  • Scanning without explicit service CBUUIDs in background mode (system ignores unfiltered background scans).
  • Ignoring canSendWriteWithoutResponse, causing silent packet drops during burst writes.
  • Performing heavy parsing or UI operations on the Core Bluetooth dispatch queue.

Review Checklist

  • NSBluetoothAlwaysUsageDescription provided in Info.plist
  • Required UIBackgroundModes configured (bluetooth-central / bluetooth-peripheral)
  • State checked for .poweredOn before issuing commands
  • Connected peripherals strongly referenced by the manager
  • Service and characteristic discovery scoped to specific [CBUUID]
  • Write type matches characteristic properties (.withResponse vs .withoutResponse)
  • State restoration identifier configured and handled in willRestoreState
  • Core Bluetooth delegate runs on a dedicated serial queue, with UI updates dispatched to @MainActor
  • Maximum packet size validated with maximumWriteValueLength

References

skills

core-bluetooth

.mcp.json

README.md

tile.json