記事の概要
今回の開発環境
PC
項目 | 内容 | 備考 |
---|---|---|
PC | MacBook Air M1 (2020) メモリ:16GB ストレージ:1TB macOS Ventura(ver 13.0) |
|
iPhone | iPhone SE(2nd) iOS 16.1 | |
IDE | Xcode ver 14.1 |
MESH
今回は 「ボタン」 を使用した
アプリの内容
- MESH の 「ボタン」 を押すと、iOS アプリの画面に 「tapped.」 「double tapped.」 と表示する。
コード (一部抜粋)
"BLEで複数デバイスとコネクトする - Qiita" 中で紹介されているコードを流用し、MESH が発した情報を取得する
※ 全体のコードは GitHub を参照してください
コード (MESH との接続に関するもの)
BLEApp.swift
import SwiftUI
import CoreBluetooth
@main
struct BLEApp: App {
@StateObject var viewModel: DeviceManager = DeviceManager()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(viewModel)
}
}
}
Device.swift
import Foundation
import CoreBluetooth
final class Device: NSObject {
let peripheral: CBPeripheral
let rssi: NSNumber
init(peripheral: CBPeripheral, rssi: NSNumber){
self.peripheral = peripheral
self.rssi = rssi
super.init()
peripheral.delegate = self
}
}
extension Device: CBPeripheralDelegate {}
DeviceManager.swift
import Foundation
import CoreBluetooth
class DeviceManager: NSObject, ObservableObject {
private let centralManager: CBCentralManager
private let services:[CBUUID] = [CBUUID(string: MESH.UUID.description)]
@Published var devices:[Device] = []
@Published var recievedData:[Int] = []
override init(){
centralManager = CBCentralManager(delegate: nil, queue: nil)
super.init()
centralManager.delegate = self
self.scan()
}
func scan(){
centralManager.scanForPeripherals(withServices: services, options: nil)
}
func stopScan(){
centralManager.stopScan()
}
func connect(perioheral: CBPeripheral){
centralManager.connect(perioheral, options: nil)
}
func disconnect(peripheral: CBPeripheral){
centralManager.cancelPeripheralConnection(peripheral)
}
func analyze(data: Data) -> [Int] {
var result:[Int] = []
data.map { i in result.append(Int(i)) }
return result
}
}
extension DeviceManager: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
centralManager.scanForPeripherals(withServices: services)
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
let device = Device(peripheral: peripheral, rssi: RSSI)
if let index = devices.firstIndex(where: { $0.peripheral.identifier == device.peripheral.identifier }) {
devices[index] = device
} else {
devices.append(device)
}
devices.map { device in self.centralManager.connect(device.peripheral, options: nil)}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
guard let peripheral = devices.first?.peripheral else { return }
peripheral.delegate = self
peripheral.discoverServices(services)
print("centralManager did connect peripheral: \(peripheral.name?.description ?? "unnnamed")")
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("centralManager did disconnect peripheral")
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
print("did update Value for executed")
print(characteristic.description)
guard let data = characteristic.value else { return }
recievedData = analyze(data: data)
}
}
extension DeviceManager: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services! {
peripheral.discoverCharacteristics(nil, for: service)
}
print("did DiscoverServices executed")
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
let byteArray: [UInt8] = [ 0x00, 0x02, 0x01, 0x03]
let data = Data(byteArray)
guard let characteristics = service.characteristics else { return }
for characteristic in characteristics {
peripheral.setNotifyValue(true, for: characteristic)
peripheral.writeValue(data, for: characteristic, type: .withResponse)
peripheral.writeValue(data, for: characteristic, type: .withoutResponse)
}
print("did Discover Characteristics for executed")
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
print("did Update Notification State For executed characteristic: \(characteristic.description)")
}
}
MESHConstant.swift
import Foundation
enum MESH: String {
case UUID = "72C90001-57A9-4D40-B746-534E22EC9F9E"
var description: String {
return rawValue
}
}
コード (iOS アプリの画面関連)
ContentView.swift
import SwiftUI
import CoreBluetooth
struct ContentView: View {
@EnvironmentObject var manager: DeviceManager
var body: some View {
VStack {
NavigationView {
List(manager.devices,id:\.self){ device in
NavigationLink {
DeviceDetailView(device: device)
} label: {
DeviceListView(device: device)
}
}
.navigationTitle(Text("Peripherals"))
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
GitHub
実際にアプリを実行 (YouTube)
開発した iOS アプリを MacBook Air (M1) 上で動かす
参考資料