Overview
블루투스와 Wi-Fi를 사용해서 유려하면서도 개인정보 보호도 되는 형태로 악세사리를 설정하고 관리할 수 있다.
API를 호출하면 새로운 근처에서 연결하려는 악세사리에 대한 피커가 뜬다.
개인정보 및 보안에 AccessorySetupKit으로 추가한 모든 악세사리를 관리할 수 있는 항목도 추가
기존에는 블루투스와 Wi-Fi를 따로 설정해야 했다.
앱은 검색 규칙과 에셋을 설정하고 모든 처리와 피커 UI는 별도 프로세스에서 처리된다.
AccessorySetupKit API
info.plist 추가
c - Supports: 지원 기술
AccessorySetupKit - Bluetooth Services
AccessorySetupKit - Bluetooth Names
AccessorySetupKit - Bluetooth Company Identifiers
악세사리를 사용하기 위해서는 발견 - 인증 - 상호 작용의 3단계가 필요하다.
ASAccessorySession
피커를 띄우려면 ASPickerDisplayItem 배열을 넘겨야 한다.
검색이 되면 ASAccessoryEvent가 전달되고 여기에 새롭게 추가된 악세사리 정보가 전달된다.
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)")
}
}
ASPickerDisplayItem 만들기
// 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
)
피커 띄우기
// Invoke accessory picker
Button {
session.showPicker(for: [pinkDisplayItem, blueDisplayItem]) { error in
if let error {
// Handle error
}
}
} label: {
Text("Add Dice")
}
페어링할 때 추가적인 보안 절차를 필요로 한다면 그것도 반영된다.
이벤트 처리
// 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)")
}
}
ASAccessory: 실제 악세사리를 나타냄
실제 악세사리 연결은 기존처럼 CoreBluetoot를 쓴다.
// 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)
}
기존에 따로 연결했던 것도 AccessorySetupKit을 쓰도록 업그레이드 할 수 있다.
이러면 새로운 Accessory설정에서 이를 볼 수 있다.
// 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
}
}
마이그레이션 아이템만 담아서 피커를 띄우면 정보 페이지가 뜨면서 마이그레이션 됐음을 알려준다.
Design for AccessorySetupKit
이미지 컨테이너 크기는 180x120pt, 이에 맞게 디자인 할 것
다크모드/라이트모드 모두에서 잘보이는지 확인할 것
투명 경계선 때문에 이미지 스케일업 했을 때 너무 작게 보일 수 있으니 주의
피커 때문에 UI가 가려지기 때문에 악세사리 설정할 때는 안보이는 곳에서 UI 업데이트 하지 말기
피커 띄우는 API는 언제든지 호출할 수 있지만 갑자기 피커가 뜨는 것보다는 맥락을 좀 더 제공하는 것을 권장한다.