스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
AccessorySetupKit 소개
AccessorySetupKit으로 액세서리 설정 경험을 향상하세요. Bluetooth 또는 Wi-Fi 액세서리 이미지를 사용하여 설정 앱으로 이동하지 않고도 페어링할 수 있게 해주는 멋진 대화상자를 만들어 보세요. 앱을 액세서리와 페어링하는 것만으로 개인정보 보호를 강화하는 방법을 알아보세요. 또한 기존 액세서리를 AccessorySetupKit으로 관리할 수 있게 마이그레이션하는 방법을 살펴보세요.
리소스
-
다운로드
저는 Apple Bluetooth 팀의 Yixin입니다
오늘은 AccessorySetupKit으로 누리는 한층 향상된 액세서리 설정 경험을 소개하게 되어 기쁩니다 먼저 개요를 살펴본 다음
API를 자세히 살펴보고 샘플 앱을 함께 만들어 봅니다
마지막으로 액세서리 선택기에서 액세서리를 근사하게 연출하는 방법에 대해 논의합니다
개요부터 시작해 보죠
액세서리는 우리 삶에서 매우 중요한 부분을 차지합니다 건강을 모니터링하는 피트니스 트래커부터 예술적 비전을 실현하는 데 도움이 되는 제작 도구가 있습니다 iOS 18과 iPadOS 18에 추가된 기능은 액세서리의 설정 경험을 더 향상하는 데 도움이 됩니다
AccessorySetupKit은 완전히 새로운 프레임워크이며 개인정보 보호를 고려한 간소화된 방식으로 앱에 액세스하여 Bluetooth와 Wi-Fi를 통해 액세서리를 설정하고 관리합니다
API를 호출하기만 하면 완전히 새로운 액세서리 선택기에 앱이 페어링하려는 근처의 액세서리들이 표시됩니다 선택기에서 액세서리에 대한 나만의 고충실도 아트워크와 친숙한 이름을 확인할 수 있습니다
탭 한 번이면 액세서리가 앱과 안전하게 페어링되어 바로 사용할 수 있습니다 지원되는 경우, 한 번의 탭으로 Bluetooth와 Wi-Fi에 모두 접근할 수 있습니다
앱은 동일한 CoreBluetooth API와 NetworkExtension API를 계속 사용하여 액세서리와 통신할 수 있습니다
개인정보 보호 및 보안 설정에 있는 Accessories 행은 모든 액세서리가 포함된 새로운 메뉴이며 AccessorySetupKit을 통해 관리됩니다 액세서리별 세부 정보 페이지에는 제품 이미지 표시 이름, 하드웨어 이름이 포함되어 사용자가 액세서리를 간단히 식별할 수 있습니다
액세서리 이름을 수정하거나 페어링된 앱의 액세스를 토글하거나 시스템에서 액세서리를 제거할 수 있습니다
새롭게 디자인된 액세서리 페이지를 Bluetooth 설정 및 Wi-Fi 설정에서 확인할 수도 있으며 액세서리가 지원하는 기술에 따라 다를 수 있습니다
iOS 18 및 iPadOS 18에서 AccessorySetupKit은 Bluetooth 및 Wi-Fi 액세서리를 지원합니다 어떻게 가능할까요? 먼저 앱이 액세서리를 설정하던 방식을 살펴보고 AccessorySetupKit과 어떤 차이가 있는지 알아봅니다
지금까지 앱은 Bluetooth 사용에 대한 액세스를 요청하여 액세서리를 검색하고 연결했습니다
액세서리가 송출하는 Wi-Fi 네트워크에 앱이 연결되려면 별도의 요청이 필요합니다
추가적인 Bluetooth 페어링 요청이 발생할 수도 있습니다 이에 반해 AccessorySetupKit은 이 모든 번거로움을 없애 개발자와 고객 모두를 만족시킵니다 탭 한 번만으로 액세서리가 앱에 페어링되어 앱에 Bluetooth와 Wi-Fi에 대한 액세스 권한이 부여됩니다 그 어느 때보다 사용자가 쉽게 이해할 수 있는 이유는 새로운 액세서리 선택기에 액세서리의 친숙한 이름과 제품 이미지가 표시되고 액세서리가 무선으로 광고하는 하드웨어 이름도 표시되기 때문입니다 이 덕분에 사용자가 설정을 탭하기 전에 먼저 액세서리의 진위를 확인할 수 있습니다 이 모든 것이 개인정보 보호를 고려한 AccessorySetupKit으로 가능합니다
앱 위로 나타나는 액세서리 선택기는 별도의 프로세스로 실행됩니다 앱은 검색 규칙과 애셋을 선택기 프로세스로 전송합니다 이러한 규칙에 Bluetooth와 Wi-Fi 인터페이스가 포함되도록 구성할 수 있으므로 액세서리에 필요한 모든 통신 액세스 권한을 단일 설정 흐름 내에서 확보할 수 있습니다
액세서리가 검색되면 선택기에 액세서리가 나타나고 탭 한 번으로 앱과 페어링됩니다
AccessorySetupKit의 개요를 살펴봤습니다 이제 API에 대해 살펴보죠 디지털 주사위를 설정하고 Bluetooth를 통해 주사위 결과를 동기화하는 앱을 만들 것이며 샘플 프로젝트를 다운로드할 수도 있습니다 디지털 주사위는 CoreBluetooth를 사용하는 앱으로 시뮬레이션합니다 샘플 앱을 디지털 주사위에 연결하고 Bluetooth GATT 서비스를 구독합니다
AccessorySetupKit을 사용하기 위해 앱의 Info.plist에 몇 가지 항목을 추가합니다 AccessorySetupKit의 Supports에 Bluetooth를 배치할 텐데 샘플 앱이 주사위와 통신하는 방식에 따른 조치입니다 Wi-Fi 역시 이 배열에서 지원되는 항목 중 하나입니다 그러고 나서 액세서리의 검색에 대한 규칙을 추가하며 이 규칙은 Bluetooth Services Wi-Fi SSID, 회사 식별자가 될 수 있습니다 주사위는 두 가지 색상이고 각 주사위가 다른 서비스 UUID를 광고하므로 UUID 두 개를 Bluetooth Services 내에 배치합니다 이제 앱에서 액세서리를 사용하는 3단계를 알려 드릴게요 액세서리를 검색하고 액세서리 사용을 승인하고 액세서리와 통신합니다 AccessorySetupKit이 검색과 승인을 처리하지만 통신은 여전히 이전 버전의 iOS와 마찬가지로 CoreBluetooth NetworkExtension으로 처리됩니다
AccessorySetupKit에서 접하게 될 첫 번째 클래스는 ASAccessorySession입니다
이 클래스는 액세서리 선택기를 표시하고 이벤트를 알리며 액세서리를 관리하는 중앙 객체입니다
ASAccessorySession에 선택기를 표시하도록 요청하면 ASPickerDisplayItem 객체의 배열이 제공됩니다
ASPickerDisplayItem은 액세서리의 이름과 이미지를 정의하며 검색 설명자도 정의하여 시스템에 스캔 방법을 알려 주는 역할을 합니다
이 덕분에 ASAccessorySession에서 showPicker를 호출하여 선택기 프로세스에서 검색과 승인을 시작할 수 있습니다 설정이 완료되면 세션 객체를 통해 앱에 ASAccessoryEvent가 전달됩니다 이벤트에 포함된 중요한 정보를 통해 새롭게 추가된 액세서리를 파악하여 앱이 액세서리와 상호작용할 수 있습니다
이제 코드를 작성해 보죠
이야기한 것처럼 먼저 ASAccessorySession을 생성합니다
세션은 API 호출을 실행하려는 DispatchQueue로 활성화되고 앱이 세션에서 이벤트를 처리하는 데 사용하는 eventHandler로 활성화됩니다
ASAccessoryEvent는 세션이나 액세서리 선택기가 업데이트될 때마다 이벤트 핸들러에 전달됩니다 다양한 이벤트가 있으므로 이벤트를 구분하려면 eventType을 확인합니다 활성화된 이벤트를 액세서리를 쿼리하는 신호로 사용할 때 세션에서 ‘accessories’ 속성을 읽는 방법을 사용하거나 새로운 설정 절차를 시작합니다 이벤트 처리는 추후에 자세히 다룰 예정이에요 이제 설정 프로세스를 시작하는 방법을 알아보기 위해 선택기 표시 항목을 생성하고 액세서리 선택기를 호출해 봅니다
표시 항목을 만들려면 제품 이름 제품 이미지, 검색 설명자가 필요합니다 ASDiscoveryDescriptor 클래스를 사용하면 모든 필수 검색 규칙을 단일 복합 객체에 결합할 수 있습니다 시스템은 스캔 결과와 일치하는 설명자 내의 모든 규칙을 비교하여 연관성 있는 정확한 액세서리를 찾아줍니다 ASDiscoveryDescriptor는 매우 유연하며 맞춤 구성이 가능한 Bluetooth 서비스 UUID Wi-Fi SSID 등의 많은 필드를 제공합니다 자세한 내용은 developer.apple.com의 문서에서 확인하세요
주사위를 검색하려면 검색 설명자에 bluetoothServiceUUID가 있어야 하며 주사위로 광고되는 GATT 서비스 UUID가 설정되어 있어야 합니다
핑크 주사위와 블루 주사위가 색상에 따라 서로 다른 서비스 UUID를 광고하기 때문에 색상별로 다른 검색 설명자를 만들기 위해 고유한 서비스 UUID를 사용하려고 합니다
그런 다음 주사위의 두 가지 색상에 해당하는 표시 항목을 생성하기 위해 이름, 이미지 해당 검색 설명자를 전달합니다 이렇게 설정하면 시스템이 두 가지 색상을 개별 액세서리로 스캔할 수 있습니다
ASPickerDisplayItem의 더 많은 속성으로 설정 경험을 맞춤화할 수 있습니다 제공되는 문서를 확인해 보세요 마지막으로 샘플 앱에는 활성화된 세션에서 showPicker를 호출하는 버튼이 있으며 우리가 만든 핑크와 블루 주사위를 표시 항목에 전달합니다 이때 액세서리 선택기가 나타나고 검색 및 설정 과정이 시작됩니다 한번 해 볼게요
책상 위에 핑크 주사위를 시뮬레이션한 휴대폰이 놓여 있습니다 샘플 앱에서 ‘Add’ 버튼을 탭하면 액세서리 선택기가 앱 위로 슬라이드되어 나타나고 핑크 주사위가 바로 검색되어 표시됩니다 이제 다른 시뮬레이터 휴대폰으로 블루 주사위를 켜면 액세서리가 검색되어 화면 가장자리를 통해 애니메이션이 추가된 것이 보입니다 선택기는 수평으로 캐러셀을 생성하여 액세서리의 멋진 애셋을 구현합니다 왼쪽과 오른쪽으로 스와이프하여 지금 설정하려는 주사위를 선택할 수 있습니다 두 색상 모두 귀엽지만 모두 핫핑크를 좋아하죠 핑크 주사위를 설정해 볼게요 연결 중이고 완료됐습니다 이제 앱에서 핑크 주사위를 사용할 수 있습니다 무척 빠르죠
액세서리 선택기에는 다양한 Bluetooth 페어링 UI가 표시됩니다 액세서리가 더 안전한 페어링 방법을 요구하면 숫자 조합 패스키 입력이 나타납니다 이제 핑크 주사위가 설정되고 다음 단계는 무엇일까요?
액세서리를 사용할 준비가 되면 앱이 accessoryAdded 이벤트를 가져옵니다 이벤트에서 액세서리 속성을 읽어 새로 설정된 주사위를 나타내는 ASAccessory 객체를 가져옵니다 일부 다른 이벤트로는 accessoryChanged가 있으며 표시 이름처럼 액세서리의 속성이 변경될 때 전송되고 설정에서 변경 가능합니다 accessoryRemoved는 액세서리가 사용자나 앱에 의해 시스템에서 제거된 경우에 전송됩니다
ASAccessory 클래스는 물리적인 액세서리를 나타냅니다 이 클래스에는 액세서리의 승인 상태 표시 이름, 검색 설명자를 비롯해 CBPeripheral의 Bluetooth 식별자 Wi-Fi 네트워크를 송출하는 경우 Wi-Fi SSID 등의 모든 네트워킹 인터페이스가 포함됩니다 accessoryAdded 이벤트에서 ASAccessory 객체를 사용하면 CoreBluetooth로 Bluetooth 주변 기기에 연결할 수 있습니다
늘 그렇듯 CBCentralManager를 만듭니다 Info.plist에서 AccessorySetupKit 지원을 선언했으니 이전 버전의 iOS와 달리 사용자에게 Bluetooth 사용 권한을 요청하지 않습니다
CBCentralManager 상태는 앱에 페어링된 액세서리가 있을 때만 poweredOn 상태가 됩니다 여기서는 핑크 주사위가 AccessorySetupKit과 페어링됩니다 핑크 주사위의 Bluetooth 주변 기기를 검색하기 위해 bluetoothIdentifier를 사용합니다 물론 언제든지 중앙 관리자의 스캔 API를 사용하여 주변 기기를 검색할 수도 있습니다 앱과 페어링된 액세서리만 스캔 결과에 반환됩니다 다음으로 주변 기기에 연결해 보겠습니다 기기가 연결되면 GATT 서비스를 검색하여 읽기와 업데이트 알림을 제공받을 수 있습니다
앱에서 Bluetooth 액세서리를 연결하는 것이 생소한 경우 developer.apple.com에 나와 있는 CoreBluetooth 문서를 통해 자세히 확인해 보세요 그럼 이제 새로 설정된 핑크 주사위에 연결해 보겠습니다
샘플 앱에서 주사위 시뮬레이터로 연결할 수 있습니다 시뮬레이터 앱을 실행하여 테스트해 보겠습니다
멋지네요! 주사위 결과가 실시간으로 샘플 앱에 동기화됩니다 AccessorySetupKit을 사용하여 액세서리를 사용하는 방법을 알아봤으며 추후에 기존 네트워킹 API를 사용하여 연결할 수 있습니다 하지만 앱이 이미 Bluetooth를 사용하도록 인증받고 AccessorySetupKit 없이 기존 액세서리를 관리하는 경우는 어떻게 할까요? 앱이 해당 권한 모델에서 AccessorySetupKit의 더 세분화된 모델로 전환하려면 어떻게 해야 할까요?
Bluetooth 주변 기기 식별자나 기존 액세서리의 Wi-Fi SSID를 사용하여 ASPickerDisplayItem의 하위 클래스인 ASMigrationDisplayItem 인스턴스를 생성할 수 있습니다 이러한 마이그레이션 항목을 showPicker 호출에 전달하여 기존 액세서리를 업그레이드하고 AccessorySetupKit에서 관리하고 새로운 액세서리 설정에서 찾을 수 있도록 합니다 showPicker 호출에 마이그레이션 항목만 포함된 경우 정보 전달 페이지가 앱 위로 노출되어 사용자에게 마이그레이션을 알립니다 마이그레이션 항목과 함께 다른 비마이그레이션 표시 항목이 전달되도록 선택하면 새 액세서리가 검색되고 설정된 경우에만 마이레이션이 발생합니다
기존 액세서리를 마이그레이션하여 AccessorySetupKit에서 관리하는 방법을 살펴봤습니다 오늘 세션을 마무리하기 전에 액세서리 설정 경험을 효과적으로 향상할 수 있는 몇 가지 권장하는 설계 실습을 보여 드리려고 합니다
액세서리 선택기는 180x120 포인트 크기의 컨테이너 박스를 제공하여 제품 이미지를 담습니다 이미지의 픽셀 해상도가 적절한지 확인하여 이미지가 화면의 모든 크기 조절 비율에서 선명하게 구현되도록 하세요
라이트 모드와 다크 모드에서 애셋이 어떻게 보이는지 테스트합니다 이미지의 배경이 투명해야 두 모드에서 근사하게 구현됩니다
이미지 주변에 투명 테두리를 활용해 보세요 시스템이 전체 이미지를 컨테이너 상자에 맞게 확장하고 투명한 테두리가 넓을수록 액세서리가 화면에 더 작게 표시됩니다 투명한 테두리를 패딩 방식으로 조정하여 선택기 UI에서 완벽한 크기의 이미지를 구현하세요
염두에 둘 것은 앱의 UI가 사용자가 액세서리를 설정하는 동안 액세서리 선택기에 가려진다는 것입니다 설정하는 동안 가려지지 않도록 UI를 업데이트하세요 pickerDidPresent와 pickerDidDismiss 이벤트를 수신하여 선택기의 표시와 표시 해제를 추적할 수 있습니다
마지막으로 중요한 점은 showPicker API를 언제든지 자유롭게 호출할 수 있지만 예기치 않은 선택기 표시를 방지하려면 사용자에게 새 액세서리를 추가한 배경에 대해 충분히 보여 주고 나서 선택기를 표시하는 것이 좋다는 것입니다 그리고 가능하면 showPicker 호출을 버튼에 통합하여 설정 경험이 항상 사용자 주도로 시작되도록 하세요
마지막으로 오늘 세션의 몇 가지 요점을 정리해 보겠습니다 AccessorySetupKit은 Bluetooth 및 Wi-Fi 액세서리를 설정하는 완전히 새로운 방법입니다 앱이 Bluetooth와 Wi-Fi를 통해 탭 한 번으로 액세서리에 액세스할 수 있습니다 사용자가 제품을 처음 경험하는 중요한 시기에 번거로움을 최소화합니다
사용하려면 AccessorySetupKit 항목을 앱의 Info.plist에 추가하면 됩니다 ASAccessorySession을 생성하고 활성화되기까지 대기한 후 작업을 시작합니다 검색하려는 액세서리별로 ASPickerDisplayItem을 생성합니다 액세서리 선택기를 표시하여 설정 절차를 시작하고 이벤트에 적절하게 응답합니다 이미 앱이 시스템 액세스를 사용하여 기존 액세서리를 관리하고 있으면 ASMigrationDisplayItem을 사용하여 액세서리를 AccessorySetupKit으로 마이그레이션합니다 애셋의 디자인에 주의를 기울여 액세서리 선택기 내에서 액세서리가 근사하게 고객에게 표시되도록 하세요
시청해 주셔서 감사합니다
-
-
6:02 - Register event handler
import AccessorySetupKit // Create a session var session = ASAccessorySession() // Activate session with event handler session.activate(on: DispatchQueue.main, eventHandler: handleSessionEvent(event:)) // Handle event func handleSessionEvent(event: ASAccessoryEvent) { switch event.eventType { case .activated: print("Session is activated and ready to use") print(session.accessories) default: print("Received event type \(event.eventType)") } }
-
7:23 - Create picker display items
// Create descriptor for pink dice let pinkDescriptor = ASDiscoveryDescriptor() pinkDescriptor.bluetoothServiceUUID = pinkUUID // Create descriptor for blue dice let blueDescriptor = ASDiscoveryDescriptor() blueDescriptor.bluetoothServiceUUID = blueUUID // Create picker display items let pinkDisplayItem = ASPickerDisplayItem( name: "Pink Dice", productImage: UIImage(named: "pink")!, descriptor: pinkDescriptor ) let blueDisplayItem = ASPickerDisplayItem( name: "Blue Dice", productImage: UIImage(named: "blue")!, descriptor: blueDescriptor )
-
8:10 - Show picker
// Invoke accessory picker Button { session.showPicker(for: [pinkDisplayItem, blueDisplayItem]) { error in if let error { // Handle error } } } label: { Text("Add Dice") }
-
9:26 - Handle events
// Handle event func handleSessionEvent(event: ASAccessoryEvent) { switch event.eventType { case .accessoryAdded: let newDice: ASAccessory = event.accessory! case .accessoryChanged: print("Accessory properties changed") case .accessoryRemoved: print("Accessory removed from system") default: print("Received event with type: \(event.eventType)") } }
-
10:22 - Communicate with accessory
// Connect to accessory using CoreBluetooth let central = CBCentralManager(delegate: self, queue: nil) func centralManagerDidUpdateState(_ central: CBCentralManager) { switch central.state { case .poweredOn: // state will only be updated to poweredOn when you have paired accessories let peripheral = central.retrievePeripherals(withIdentifiers: [newDice.bluetoothIdentifier]).first central.connect(peripheral) default: print("Received event type \(event.eventType)") } } func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { peripheral.delegate = self peripheral.discoverServices(pinkUUID) }
-
11:58 - Migrate existing accessories
// Create migration items let pinkMigration = ASMigrationDisplayItem(name: "Pink Dice", productImage: UIImage(named: "pink")!, descriptor: pinkDescriptor) pinkMigration.peripheralIdentifier = pinkPeripheral.identifier // Present picker with migration items session.showPicker(for: [pinkMigration]) { error in if let error { // Handle error } }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.