{"id":"69f5087c-e38b-48bf-8b7a-6e0b35aded58","shortId":"QEgnme","kind":"skill","title":"accessorysetupkit","tagline":"Discover and configure Bluetooth and Wi-Fi accessories using AccessorySetupKit. Use when presenting a privacy-preserving accessory picker, defining discovery descriptors for BLE or Wi-Fi devices, handling accessory session events, migrating from CoreBluetooth permission-based sca","description":"# AccessorySetupKit\n\nPrivacy-preserving accessory discovery and setup for Bluetooth and Wi-Fi\ndevices. Replaces broad Bluetooth/Wi-Fi permission prompts with a\nsystem-provided picker that grants per-accessory access with a single tap.\nAvailable iOS 18+ / Swift 6.3.\n\nAfter setup, apps continue using CoreBluetooth and NetworkExtension for\ncommunication. AccessorySetupKit handles only the discovery and authorization\nstep.\n\n## Contents\n\n- [Setup and Entitlements](#setup-and-entitlements)\n- [Discovery Descriptors](#discovery-descriptors)\n- [Presenting the Picker](#presenting-the-picker)\n- [Event Handling](#event-handling)\n- [Bluetooth Accessories](#bluetooth-accessories)\n- [Wi-Fi Accessories](#wi-fi-accessories)\n- [Migration from CoreBluetooth](#migration-from-corebluetooth)\n- [Common Mistakes](#common-mistakes)\n- [Review Checklist](#review-checklist)\n- [References](#references)\n\n## Setup and Entitlements\n\n### Info.plist Configuration\n\nAdd these keys to the app's Info.plist:\n\n| Key | Type | Purpose |\n|---|---|---|\n| `NSAccessorySetupSupports` | `[String]` | Required. Array containing `Bluetooth` and/or `WiFi` |\n| `NSAccessorySetupBluetoothServices` | `[String]` | Service UUIDs the app discovers (Bluetooth) |\n| `NSAccessorySetupBluetoothNames` | `[String]` | Bluetooth names or substrings to match |\n| `NSAccessorySetupBluetoothCompanyIdentifiers` | `[Number]` | Bluetooth company identifiers |\n\nThe Bluetooth-specific keys must match the values used in `ASDiscoveryDescriptor`.\nIf the app uses identifiers, names, or services not declared in Info.plist, the\napp crashes at discovery time.\n\n### No Bluetooth Permission Required\n\nWhen an app declares `NSAccessorySetupSupports` with `Bluetooth`, creating a\n`CBCentralManager` no longer triggers the system Bluetooth permission dialog.\nThe central manager's state transitions to `poweredOn` only when the app has\nat least one paired accessory via AccessorySetupKit.\n\n## Discovery Descriptors\n\n`ASDiscoveryDescriptor` defines the matching criteria for finding accessories.\nThe system matches scanned results against all rules in the descriptor to\nfilter for the target accessory.\n\n### Bluetooth Descriptor\n\n```swift\nimport AccessorySetupKit\nimport CoreBluetooth\n\nvar descriptor = ASDiscoveryDescriptor()\ndescriptor.bluetoothServiceUUID = CBUUID(string: \"12345678-1234-1234-1234-123456789ABC\")\ndescriptor.bluetoothNameSubstring = \"MyDevice\"\ndescriptor.bluetoothRange = .immediate  // Only nearby devices\n```\n\nA Bluetooth descriptor requires `bluetoothCompanyIdentifier` or\n`bluetoothServiceUUID`, plus at least one of:\n\n- `bluetoothNameSubstring`\n- `bluetoothManufacturerDataBlob` and `bluetoothManufacturerDataMask` (same length)\n- `bluetoothServiceDataBlob` and `bluetoothServiceDataMask` (same length)\n\n### Wi-Fi Descriptor\n\n```swift\nvar descriptor = ASDiscoveryDescriptor()\ndescriptor.ssid = \"MyAccessory-Network\"\n// OR use a prefix:\n// descriptor.ssidPrefix = \"MyAccessory-\"\n```\n\nSupply either `ssid` or `ssidPrefix`, not both. The app crashes if both are set.\nThe `ssidPrefix` must have a non-zero length.\n\n### Bluetooth Range\n\nControl the physical proximity required for discovery:\n\n| Value | Behavior |\n|---|---|\n| `.default` | Standard Bluetooth range |\n| `.immediate` | Only accessories in close physical proximity |\n\n### Support Options\n\nSet `supportedOptions` on the descriptor to declare the accessory's capabilities:\n\n```swift\ndescriptor.supportedOptions = [.bluetoothPairingLE, .bluetoothTransportBridging]\n```\n\n| Option | Purpose |\n|---|---|\n| `.bluetoothPairingLE` | BLE pairing support |\n| `.bluetoothTransportBridging` | Bluetooth transport bridging |\n| `.bluetoothHID` | Bluetooth HID device |\n\n## Presenting the Picker\n\n### Creating the Session\n\nCreate and activate an `ASAccessorySession` to manage discovery lifecycle:\n\n```swift\nimport AccessorySetupKit\n\nfinal class AccessoryManager {\n    private let session = ASAccessorySession()\n\n    func start() {\n        session.activate(on: .main) { [weak self] event in\n            self?.handleEvent(event)\n        }\n    }\n\n    private func handleEvent(_ event: ASAccessoryEvent) {\n        switch event.eventType {\n        case .activated:\n            // Session ready. Check session.accessories for previously paired devices.\n            break\n        case .accessoryAdded:\n            guard let accessory = event.accessory else { return }\n            handleAccessoryAdded(accessory)\n        case .accessoryChanged:\n            // Accessory properties changed (e.g., display name updated in Settings)\n            break\n        case .accessoryRemoved:\n            // Accessory removed by user or app\n            break\n        case .invalidated:\n            // Session invalidated, cannot be reused\n            break\n        default:\n            break\n        }\n    }\n}\n```\n\n### Showing the Picker\n\nCreate `ASPickerDisplayItem` instances with a name, product image, and\ndiscovery descriptor, then pass them to the session:\n\n```swift\nfunc showAccessoryPicker() {\n    var descriptor = ASDiscoveryDescriptor()\n    descriptor.bluetoothServiceUUID = CBUUID(string: \"ABCD1234-0000-1000-8000-00805F9B34FB\")\n\n    guard let image = UIImage(named: \"my-accessory\") else { return }\n\n    let item = ASPickerDisplayItem(\n        name: \"My Bluetooth Accessory\",\n        productImage: image,\n        descriptor: descriptor\n    )\n\n    session.showPicker(for: [item]) { error in\n        if let error {\n            print(\"Picker failed: \\(error.localizedDescription)\")\n        }\n    }\n}\n```\n\nThe picker runs in a separate system process. It shows each matching device\nas a separate item. When multiple devices match a given descriptor, the picker\ncreates a horizontal carousel.\n\n### Setup Options\n\nConfigure picker behavior per display item:\n\n```swift\nvar item = ASPickerDisplayItem(\n    name: \"My Accessory\",\n    productImage: image,\n    descriptor: descriptor\n)\nitem.setupOptions = [.rename, .confirmAuthorization]\n```\n\n| Option | Effect |\n|---|---|\n| `.rename` | Allow renaming the accessory during setup |\n| `.confirmAuthorization` | Show authorization confirmation before setup |\n| `.finishInApp` | Signal that setup continues in the app after pairing |\n\n### Product Images\n\nThe picker displays images in a 180x120 point container. Best practices:\n\n- Use high-resolution images for all screen scale factors\n- Use transparent backgrounds for correct light/dark mode appearance\n- Adjust transparent borders as padding to control apparent accessory size\n- Test in both light and dark mode\n\n## Event Handling\n\n### Event Types\n\nThe session delivers `ASAccessoryEvent` objects through the event handler:\n\n| Event | When |\n|---|---|\n| `.activated` | Session is active, query `session.accessories` |\n| `.accessoryAdded` | User selected an accessory in the picker |\n| `.accessoryChanged` | Accessory properties updated (e.g., renamed) |\n| `.accessoryRemoved` | Accessory removed from system |\n| `.invalidated` | Session invalidated, create a new one |\n| `.migrationComplete` | Migration of legacy accessories completed |\n| `.pickerDidPresent` | Picker appeared on screen |\n| `.pickerDidDismiss` | Picker dismissed |\n| `.pickerSetupBridging` | Transport bridging setup in progress |\n| `.pickerSetupPairing` | Bluetooth pairing in progress |\n| `.pickerSetupFailed` | Setup failed |\n| `.pickerSetupRename` | User is renaming the accessory |\n| `.accessoryDiscovered` | New accessory found (custom filtering mode) |\n\n### Coordinating Picker Dismissal\n\nWhen the user selects an accessory, `.accessoryAdded` fires before\n`.pickerDidDismiss`. To show custom setup UI after the picker closes, store the\naccessory on the first event and act on it after dismissal:\n\n```swift\nprivate var pendingAccessory: ASAccessory?\n\nprivate func handleEvent(_ event: ASAccessoryEvent) {\n    switch event.eventType {\n    case .accessoryAdded:\n        pendingAccessory = event.accessory\n    case .pickerDidDismiss:\n        if let accessory = pendingAccessory {\n            pendingAccessory = nil\n            beginCustomSetup(accessory)\n        }\n    default:\n        break\n    }\n}\n```\n\n## Bluetooth Accessories\n\nAfter an accessory is added via the picker, use CoreBluetooth to communicate.\nThe `bluetoothIdentifier` on the `ASAccessory` maps to a `CBPeripheral`.\n\n```swift\nimport CoreBluetooth\n\nfunc handleAccessoryAdded(_ accessory: ASAccessory) {\n    guard let btIdentifier = accessory.bluetoothIdentifier else { return }\n\n    // Create CBCentralManager — no Bluetooth permission prompt appears\n    let centralManager = CBCentralManager(delegate: self, queue: nil)\n\n    // After poweredOn, retrieve the peripheral\n    let peripherals = centralManager.retrievePeripherals(\n        withIdentifiers: [btIdentifier]\n    )\n    guard let peripheral = peripherals.first else { return }\n    centralManager.connect(peripheral, options: nil)\n}\n```\n\nKey points:\n\n- `CBCentralManager` state reaches `.poweredOn` only when the app has paired accessories\n- Scanning with `scanForPeripherals(withServices:)` returns only\n  accessories paired through AccessorySetupKit\n- No `NSBluetoothAlwaysUsageDescription` is needed when using AccessorySetupKit\n  exclusively\n\n## Wi-Fi Accessories\n\nFor Wi-Fi accessories, the `ssid` on the `ASAccessory` identifies the network.\nUse `NEHotspotConfiguration` from NetworkExtension to join it:\n\n```swift\nimport NetworkExtension\n\nfunc handleWiFiAccessoryAdded(_ accessory: ASAccessory) {\n    guard let ssid = accessory.ssid else { return }\n\n    let configuration = NEHotspotConfiguration(ssid: ssid)\n    NEHotspotConfigurationManager.shared.apply(configuration) { error in\n        if let error {\n            print(\"Wi-Fi join failed: \\(error.localizedDescription)\")\n        }\n    }\n}\n```\n\nBecause the accessory was discovered through AccessorySetupKit, joining the\nnetwork does not trigger the standard Wi-Fi access prompt.\n\n## Migration from CoreBluetooth\n\nApps with existing CoreBluetooth-authorized accessories can migrate them to\nAccessorySetupKit using `ASMigrationDisplayItem`. This is a one-time operation\nthat registers known accessories in the new system.\n\n```swift\nfunc migrateExistingAccessories() {\n    guard let image = UIImage(named: \"my-accessory\") else { return }\n\n    var descriptor = ASDiscoveryDescriptor()\n    descriptor.bluetoothServiceUUID = CBUUID(string: \"ABCD1234-0000-1000-8000-00805F9B34FB\")\n\n    let migrationItem = ASMigrationDisplayItem(\n        name: \"My Accessory\",\n        productImage: image,\n        descriptor: descriptor\n    )\n    // Set the peripheral identifier from CoreBluetooth\n    migrationItem.peripheralIdentifier = existingPeripheralUUID\n\n    // For Wi-Fi accessories:\n    // migrationItem.hotspotSSID = \"MyAccessory-WiFi\"\n\n    session.showPicker(for: [migrationItem]) { error in\n        if let error {\n            print(\"Migration failed: \\(error.localizedDescription)\")\n        }\n    }\n}\n```\n\nMigration rules:\n\n- If `showPicker` contains only migration items, the system shows an\n  informational page instead of a discovery picker\n- If migration items are mixed with regular display items, migration happens\n  only when a new accessory is discovered and set up\n- Do not initialize `CBCentralManager` before migration completes — doing so\n  causes an error and the picker fails to appear\n- The session receives `.migrationComplete` when migration finishes\n\n## Common Mistakes\n\n### DON'T: Omit Info.plist keys for Bluetooth discovery\n\nThe app crashes if it uses identifiers, names, or services in descriptors that\nare not declared in Info.plist.\n\n```swift\n// WRONG — service UUID not in NSAccessorySetupBluetoothServices\nvar descriptor = ASDiscoveryDescriptor()\ndescriptor.bluetoothServiceUUID = CBUUID(string: \"UNDECLARED-UUID\")\nsession.showPicker(for: [item]) { _ in }  // Crash\n\n// CORRECT — declare all UUIDs in Info.plist first\n// Info.plist: NSAccessorySetupBluetoothServices = [\"ABCD1234-...\"]\nvar descriptor = ASDiscoveryDescriptor()\ndescriptor.bluetoothServiceUUID = CBUUID(string: \"ABCD1234-...\")\n```\n\n### DON'T: Set both ssid and ssidPrefix\n\n```swift\n// WRONG — crashes at runtime\nvar descriptor = ASDiscoveryDescriptor()\ndescriptor.ssid = \"MyNetwork\"\ndescriptor.ssidPrefix = \"My\"  // Cannot set both\n\n// CORRECT — use one or the other\nvar descriptor = ASDiscoveryDescriptor()\ndescriptor.ssid = \"MyNetwork\"\n```\n\n### DON'T: Initialize CBCentralManager before migration\n\n```swift\n// WRONG — migration fails, picker does not appear\nlet central = CBCentralManager(delegate: self, queue: nil)\nsession.showPicker(for: [migrationItem]) { error in\n    // error is non-nil\n}\n\n// CORRECT — wait for .migrationComplete before using CoreBluetooth\nsession.activate(on: .main) { event in\n    if event.eventType == .migrationComplete {\n        let central = CBCentralManager(delegate: self, queue: nil)\n    }\n}\n```\n\n### DON'T: Show the picker without user intent\n\n```swift\n// WRONG — picker appears unexpectedly on app launch\noverride func viewDidLoad() {\n    super.viewDidLoad()\n    session.showPicker(for: items) { _ in }\n}\n\n// CORRECT — bind picker to a user action\n@IBAction func addAccessoryTapped(_ sender: UIButton) {\n    session.showPicker(for: items) { _ in }\n}\n```\n\n### DON'T: Reuse an invalidated session\n\n```swift\n// WRONG — session is dead after invalidation\nsession.showPicker(for: items) { _ in }  // No effect\n\n// CORRECT — create a new session\nlet newSession = ASAccessorySession()\nnewSession.activate(on: .main) { event in\n    // Handle events\n}\n```\n\n## Review Checklist\n\n- [ ] `NSAccessorySetupSupports` added to Info.plist with `Bluetooth` and/or `WiFi`\n- [ ] Bluetooth-specific plist keys (`NSAccessorySetupBluetoothServices`, `NSAccessorySetupBluetoothNames`, `NSAccessorySetupBluetoothCompanyIdentifiers`) match descriptor values\n- [ ] Session activated before calling `showPicker`\n- [ ] Event handler uses `[weak self]` to avoid retain cycles\n- [ ] All `ASAccessoryEventType` cases handled, including `@unknown default`\n- [ ] Product images use transparent backgrounds and appropriate resolution\n- [ ] `ssid` and `ssidPrefix` are never set simultaneously on a descriptor\n- [ ] Picker presentation tied to explicit user action, not automatic\n- [ ] `CBCentralManager` not initialized until after migration completes (if migrating)\n- [ ] `bluetoothIdentifier` or `ssid` from `ASAccessory` used to connect post-setup\n- [ ] Invalidated sessions replaced with new instances\n- [ ] Accessory removal events handled to clean up app state\n\n## References\n\n- Extended patterns (custom filtering, batch setup, removal handling, error recovery): [references/accessorysetupkit-patterns.md](references/accessorysetupkit-patterns.md)\n- [AccessorySetupKit framework](https://sosumi.ai/documentation/accessorysetupkit)\n- [ASAccessorySession](https://sosumi.ai/documentation/accessorysetupkit/asaccessorysession)\n- [ASDiscoveryDescriptor](https://sosumi.ai/documentation/accessorysetupkit/asdiscoverydescriptor)\n- [ASPickerDisplayItem](https://sosumi.ai/documentation/accessorysetupkit/aspickerdisplayitem)\n- [ASAccessory](https://sosumi.ai/documentation/accessorysetupkit/asaccessory)\n- [ASAccessoryEvent](https://sosumi.ai/documentation/accessorysetupkit/asaccessoryevent)\n- [ASMigrationDisplayItem](https://sosumi.ai/documentation/accessorysetupkit/asmigrationdisplayitem)\n- [Discovering and configuring accessories](https://sosumi.ai/documentation/accessorysetupkit/discovering-and-configuring-accessories)\n- [Setting up and authorizing a Bluetooth accessory](https://sosumi.ai/documentation/accessorysetupkit/setting-up-and-authorizing-a-bluetooth-accessory)\n- [Meet AccessorySetupKit — WWDC24](https://sosumi.ai/videos/play/wwdc2024/10203/)","tags":["accessorysetupkit","swift","ios","skills","dpearson2699","accessibility","agent-skills","ai-coding","apple","claude-code","codex-skills","cursor-skills"],"capabilities":["skill","source-dpearson2699","skill-accessorysetupkit","topic-accessibility","topic-agent-skills","topic-ai-coding","topic-apple","topic-claude-code","topic-codex-skills","topic-cursor-skills","topic-ios","topic-ios-development","topic-liquid-glass","topic-localization","topic-mapkit"],"categories":["swift-ios-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/dpearson2699/swift-ios-skills/accessorysetupkit","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add dpearson2699/swift-ios-skills","source_repo":"https://github.com/dpearson2699/swift-ios-skills","install_from":"skills.sh"}},"qualityScore":"0.684","qualityRationale":"deterministic score 0.68 from registry signals: · indexed on github topic:agent-skills · 468 github stars · SKILL.md body (15,585 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T00:53:40.942Z","embedding":null,"createdAt":"2026-04-18T22:00:38.439Z","updatedAt":"2026-04-22T00:53:40.942Z","lastSeenAt":"2026-04-22T00:53:40.942Z","tsv":"'-0000':572,1115 '-00805':575,1118 '-1000':573,1116 '-1234':317,318,319 '-123456789':320 '-8000':574,1117 '/documentation/accessorysetupkit)':1571 '/documentation/accessorysetupkit/asaccessory)':1587 '/documentation/accessorysetupkit/asaccessoryevent)':1591 '/documentation/accessorysetupkit/asaccessorysession)':1575 '/documentation/accessorysetupkit/asdiscoverydescriptor)':1579 '/documentation/accessorysetupkit/asmigrationdisplayitem)':1595 '/documentation/accessorysetupkit/aspickerdisplayitem)':1583 '/documentation/accessorysetupkit/discovering-and-configuring-accessories)':1602 '/documentation/accessorysetupkit/setting-up-and-authorizing-a-bluetooth-accessory)':1612 '/videos/play/wwdc2024/10203/)':1618 '12345678':316 '18':81 '180x120':695 '6.3':83 'abc':321 'abcd1234':571,1114,1282,1289 'access':74,1061 'accessori':10,20,33,47,73,128,131,135,139,273,285,302,410,425,505,510,513,525,584,593,654,668,726,760,765,771,786,815,818,831,847,878,883,887,890,914,968,975,990,995,1016,1045,1072,1090,1105,1125,1142,1193,1545,1599,1609 'accessory.bluetoothidentifier':919 'accessory.ssid':1021 'accessoryad':502,756,832,871 'accessorychang':512,764 'accessorydiscov':816 'accessorymanag':466 'accessoryremov':524,770 'accessorysetupkit':1,12,43,94,275,307,463,978,985,1049,1077,1567,1614 'act':853 'action':1406,1516 'activ':454,491,750,753,1472 'ad':892,1453 'add':164 'addaccessorytap':1409 'adjust':718 'allow':665 'and/or':181,1458 'app':86,169,188,218,229,240,267,378,530,684,965,1066,1235,1390,1552 'appar':725 'appear':717,790,928,1216,1336,1387 'appropri':1498 'array':178 'asaccessori':862,904,915,1000,1017,1532,1584 'asaccessoryev':487,742,867,1588 'asaccessoryeventtyp':1486 'asaccessorysess':456,470,1442,1572 'asdiscoverydescriptor':215,278,312,359,567,1110,1261,1285,1304,1320,1576 'asmigrationdisplayitem':1079,1122,1592 'aspickerdisplayitem':546,589,651,1580 'author':100,673,1071,1606 'automat':1518 'avail':79 'avoid':1482 'background':712,1496 'base':41 'batch':1559 'begincustomsetup':882 'behavior':403,644 'best':698 'bind':1401 'ble':26,435 'bluetooth':5,52,127,130,180,190,193,201,206,235,244,253,303,330,393,406,439,443,592,803,886,925,1232,1457,1461,1608 'bluetooth-accessori':129 'bluetooth-specif':205,1460 'bluetooth/wi-fi':60 'bluetoothcompanyidentifi':333 'bluetoothhid':442 'bluetoothidentifi':901,1528 'bluetoothmanufacturerdatablob':342 'bluetoothmanufacturerdatamask':344 'bluetoothnamesubstr':341 'bluetoothpairingl':430,434 'bluetoothservicedatablob':347 'bluetoothservicedatamask':349 'bluetoothserviceuuid':335 'bluetoothtransportbridg':431,438 'border':720 'break':500,522,531,539,541,885 'bridg':441,798 'broad':59 'btidentifi':918,945 'call':1474 'cannot':536,1309 'capabl':427 'carousel':639 'case':490,501,511,523,532,870,874,1487 'caus':1208 'cbcentralmanag':247,923,931,958,1202,1326,1339,1371,1519 'cbperipher':908 'cbuuid':314,569,1112,1263,1287 'central':257,1338,1370 'centralmanag':930 'centralmanager.connect':952 'centralmanager.retrieveperipherals':943 'chang':515 'check':494 'checklist':153,156,1451 'class':465 'clean':1550 'close':412,844 'common':147,150,1224 'common-mistak':149 'communic':93,899 'compani':202 'complet':787,1205,1525 'configur':4,163,642,1025,1030,1598 'confirm':674 'confirmauthor':661,671 'connect':1535 'contain':179,697,1163 'content':102 'continu':87,681 'control':395,724 'coordin':823 'corebluetooth':38,89,142,146,309,897,911,1065,1070,1135,1360 'corebluetooth-author':1069 'correct':714,1273,1312,1354,1400,1435 'crash':230,379,1236,1272,1299 'creat':245,449,452,545,636,778,922,1436 'criteria':282 'custom':820,838,1557 'cycl':1484 'dark':733 'dead':1426 'declar':225,241,423,1249,1274 'default':404,540,884,1491 'defin':22,279 'deleg':932,1340,1372 'deliv':741 'descriptor':24,111,114,277,296,304,311,331,355,358,421,555,566,596,597,633,657,658,1109,1128,1129,1245,1260,1284,1303,1319,1469,1509 'descriptor.bluetoothnamesubstring':322 'descriptor.bluetoothrange':324 'descriptor.bluetoothserviceuuid':313,568,1111,1262,1286 'descriptor.ssid':360,1305,1321 'descriptor.ssidprefix':368,1307 'descriptor.supportedoptions':429 'devic':31,57,328,445,499,622,629 'dialog':255 'discov':2,189,1047,1195,1596 'discoveri':23,48,98,110,113,232,276,401,459,554,1176,1233 'discovery-descriptor':112 'dismiss':795,825,857 'display':517,646,691,1185 'e.g':516,768 'effect':663,1434 'either':371 'els':507,585,920,950,1022,1106 'entitl':105,109,161 'error':601,605,1031,1035,1150,1154,1210,1347,1349,1563 'error.localizeddescription':609,1042,1158 'event':35,122,125,478,482,486,735,737,746,748,851,866,1364,1446,1449,1476,1547 'event-handl':124 'event.accessory':506,873 'event.eventtype':489,869,1367 'exclus':986 'exist':1068 'existingperipheraluuid':1137 'explicit':1514 'extend':1555 'f9b34fb':576,1119 'factor':709 'fail':608,809,1041,1157,1214,1332 'fi':9,30,56,134,138,354,989,994,1039,1060,1141 'filter':298,821,1558 'final':464 'find':284 'finish':1223 'finishinapp':677 'fire':833 'first':850,1279 'found':819 'framework':1568 'func':471,484,563,864,912,1014,1096,1393,1408 'given':632 'grant':70 'guard':503,577,916,946,1018,1098 'handl':32,95,123,126,736,1448,1488,1548,1562 'handleaccessoryad':509,913 'handleev':481,485,865 'handler':747,1477 'handlewifiaccessoryad':1015 'happen':1188 'hid':444 'high':702 'high-resolut':701 'horizont':638 'ibact':1407 'identifi':203,220,1001,1133,1240 'imag':552,579,595,656,688,692,704,1100,1127,1493 'immedi':325,408 'import':306,308,462,910,1012 'includ':1489 'info.plist':162,171,227,1229,1251,1278,1280,1455 'inform':1171 'initi':1201,1325,1521 'instanc':547,1544 'instead':1173 'intent':1383 'invalid':533,535,775,777,1420,1428,1539 'io':80 'item':588,600,626,647,650,1166,1180,1186,1270,1398,1414,1431 'item.setupoptions':659 'join':1009,1040,1050 'key':166,172,208,956,1230,1464 'known':1089 'launch':1391 'least':270,338 'legaci':785 'length':346,351,392 'let':468,504,578,587,604,877,917,929,941,947,1019,1024,1034,1099,1120,1153,1337,1369,1440 'lifecycl':460 'light':731 'light/dark':715 'longer':249 'main':475,1363,1445 'manag':258,458 'map':905 'match':198,210,281,288,621,630,1468 'meet':1613 'migrat':36,140,144,783,1063,1074,1156,1159,1165,1179,1187,1204,1222,1328,1331,1524,1527 'migrateexistingaccessori':1097 'migration-from-corebluetooth':143 'migrationcomplet':782,1220,1357,1368 'migrationitem':1121,1149,1346 'migrationitem.hotspotssid':1143 'migrationitem.peripheralidentifier':1136 'mistak':148,151,1225 'mix':1182 'mode':716,734,822 'multipl':628 'must':209,386 'my-accessori':582,1103 'myaccessori':362,369,1145 'myaccessory-network':361 'myaccessory-wifi':1144 'mydevic':323 'mynetwork':1306,1322 'name':194,221,518,550,581,590,652,1102,1123,1241 'nearbi':327 'need':982 'nehotspotconfigur':1005,1026 'nehotspotconfigurationmanager.shared.apply':1029 'network':363,1003,1052 'networkextens':91,1007,1013 'never':1504 'new':780,817,1093,1192,1438,1543 'newsess':1441 'newsession.activate':1443 'nil':881,935,955,1343,1353,1375 'non':390,1352 'non-nil':1351 'non-zero':389 'nsaccessorysetupbluetoothcompanyidentifi':199,1467 'nsaccessorysetupbluetoothnam':191,1466 'nsaccessorysetupbluetoothservic':183,1258,1281,1465 'nsaccessorysetupsupport':175,242,1452 'nsbluetoothalwaysusagedescript':980 'number':200 'object':743 'omit':1228 'one':271,339,781,1084,1314 'one-tim':1083 'oper':1086 'option':416,432,641,662,954 'overrid':1392 'pad':722 'page':1172 'pair':272,436,498,686,804,967,976 'pass':557 'pattern':1556 'pendingaccessori':861,872,879,880 'per':72,645 'per-accessori':71 'peripher':940,942,948,953,1132 'peripherals.first':949 'permiss':40,61,236,254,926 'permission-bas':39 'physic':397,413 'picker':21,68,117,121,448,544,607,611,635,643,690,763,789,794,824,843,895,1177,1213,1333,1380,1386,1402,1510 'pickerdiddismiss':793,835,875 'pickerdidpres':788 'pickersetupbridg':796 'pickersetupfail':807 'pickersetuppair':802 'pickersetuprenam':810 'plist':1463 'plus':336 'point':696,957 'post':1537 'post-setup':1536 'poweredon':263,937,961 'practic':699 'prefix':367 'present':15,115,119,446,1511 'presenting-the-pick':118 'preserv':19,46 'previous':497 'print':606,1036,1155 'privaci':18,45 'privacy-preserv':17,44 'privat':467,483,859,863 'process':617 'product':551,687,1492 'productimag':594,655,1126 'progress':801,806 'prompt':62,927,1062 'properti':514,766 'provid':67 'proxim':398,414 'purpos':174,433 'queri':754 'queue':934,1342,1374 'rang':394,407 'reach':960 'readi':493 'receiv':1219 'recoveri':1564 'refer':157,158,1554 'references/accessorysetupkit-patterns.md':1565,1566 'regist':1088 'regular':1184 'remov':526,772,1546,1561 'renam':660,664,666,769,813 'replac':58,1541 'requir':177,237,332,399 'resolut':703,1499 'result':290 'retain':1483 'retriev':938 'return':508,586,921,951,973,1023,1107 'reus':538,1418 'review':152,155,1450 'review-checklist':154 'rule':293,1160 'run':612 'runtim':1301 'sca':42 'scale':708 'scan':289,969 'scanforperipher':971 'screen':707,792 'select':758,829 'self':477,480,933,1341,1373,1480 'sender':1410 'separ':615,625 'servic':185,223,1243,1254 'session':34,451,469,492,534,561,740,751,776,1218,1421,1424,1439,1471,1540 'session.accessories':495,755 'session.activate':473,1361 'session.showpicker':598,1147,1268,1344,1396,1412,1429 'set':383,417,521,1130,1197,1292,1310,1505,1603 'setup':50,85,103,107,159,640,670,676,680,799,808,839,1538,1560 'setup-and-entitl':106 'show':542,619,672,837,1169,1378 'showaccessorypick':564 'showpick':1162,1475 'signal':678 'simultan':1506 'singl':77 'size':727 'skill' 'skill-accessorysetupkit' 'sosumi.ai':1570,1574,1578,1582,1586,1590,1594,1601,1611,1617 'sosumi.ai/documentation/accessorysetupkit)':1569 'sosumi.ai/documentation/accessorysetupkit/asaccessory)':1585 'sosumi.ai/documentation/accessorysetupkit/asaccessoryevent)':1589 'sosumi.ai/documentation/accessorysetupkit/asaccessorysession)':1573 'sosumi.ai/documentation/accessorysetupkit/asdiscoverydescriptor)':1577 'sosumi.ai/documentation/accessorysetupkit/asmigrationdisplayitem)':1593 'sosumi.ai/documentation/accessorysetupkit/aspickerdisplayitem)':1581 'sosumi.ai/documentation/accessorysetupkit/discovering-and-configuring-accessories)':1600 'sosumi.ai/documentation/accessorysetupkit/setting-up-and-authorizing-a-bluetooth-accessory)':1610 'sosumi.ai/videos/play/wwdc2024/10203/)':1616 'source-dpearson2699' 'specif':207,1462 'ssid':372,997,1020,1027,1028,1294,1500,1530 'ssidprefix':374,385,1296,1502 'standard':405,1057 'start':472 'state':260,959,1553 'step':101 'store':845 'string':176,184,192,315,570,1113,1264,1288 'substr':196 'super.viewdidload':1395 'suppli':370 'support':415,437 'supportedopt':418 'swift':82,305,356,428,461,562,648,858,909,1011,1095,1252,1297,1329,1384,1422 'switch':488,868 'system':66,252,287,616,774,1094,1168 'system-provid':65 'tap':78 'target':301 'test':728 'tie':1512 'time':233,1085 'topic-accessibility' 'topic-agent-skills' 'topic-ai-coding' 'topic-apple' 'topic-claude-code' 'topic-codex-skills' 'topic-cursor-skills' 'topic-ios' 'topic-ios-development' 'topic-liquid-glass' 'topic-localization' 'topic-mapkit' 'transit':261 'transpar':711,719,1495 'transport':440,797 'trigger':250,1055 'type':173,738 'ui':840 'uibutton':1411 'uiimag':580,1101 'undeclar':1266 'undeclared-uuid':1265 'unexpect':1388 'unknown':1490 'updat':519,767 'use':11,13,88,213,219,365,700,710,896,984,1004,1078,1239,1313,1359,1478,1494,1533 'user':528,757,811,828,1382,1405,1515 'uuid':186,1255,1267,1276 'valu':212,402,1470 'var':310,357,565,649,860,1108,1259,1283,1302,1318 'via':274,893 'viewdidload':1394 'wait':1355 'weak':476,1479 'wi':8,29,55,133,137,353,988,993,1038,1059,1140 'wi-fi':7,28,54,132,352,987,992,1037,1058,1139 'wi-fi-accessori':136 'wifi':182,1146,1459 'withidentifi':944 'without':1381 'withservic':972 'wrong':1253,1298,1330,1385,1423 'wwdc24':1615 'zero':391","prices":[{"id":"3e388b49-a713-4707-b800-514b79ef1d2f","listingId":"69f5087c-e38b-48bf-8b7a-6e0b35aded58","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"dpearson2699","category":"swift-ios-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:00:38.439Z"}],"sources":[{"listingId":"69f5087c-e38b-48bf-8b7a-6e0b35aded58","source":"github","sourceId":"dpearson2699/swift-ios-skills/accessorysetupkit","sourceUrl":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/accessorysetupkit","isPrimary":false,"firstSeenAt":"2026-04-18T22:00:38.439Z","lastSeenAt":"2026-04-22T00:53:40.942Z"}],"details":{"listingId":"69f5087c-e38b-48bf-8b7a-6e0b35aded58","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"dpearson2699","slug":"accessorysetupkit","github":{"repo":"dpearson2699/swift-ios-skills","stars":468,"topics":["accessibility","agent-skills","ai-coding","apple","claude-code","codex-skills","cursor-skills","ios","ios-development","liquid-glass","localization","mapkit","networking","storekit","swift","swift-concurrency","swiftdata","swiftui","widgetkit","xcode"],"license":"other","html_url":"https://github.com/dpearson2699/swift-ios-skills","pushed_at":"2026-04-21T19:26:16Z","description":"Agent Skills for iOS 26+, Swift 6.3, SwiftUI, and modern Apple frameworks","skill_md_sha":"01c31f56674d1276954db87ee8d3376e36c4f101","skill_md_path":"skills/accessorysetupkit/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/accessorysetupkit"},"layout":"multi","source":"github","category":"swift-ios-skills","frontmatter":{"name":"accessorysetupkit","description":"Discover and configure Bluetooth and Wi-Fi accessories using AccessorySetupKit. Use when presenting a privacy-preserving accessory picker, defining discovery descriptors for BLE or Wi-Fi devices, handling accessory session events, migrating from CoreBluetooth permission-based scanning, or setting up accessories without requiring broad Bluetooth permissions."},"skills_sh_url":"https://skills.sh/dpearson2699/swift-ios-skills/accessorysetupkit"},"updatedAt":"2026-04-22T00:53:40.942Z"}}