実現したいこと
Appleが提供しているTransferring Data Between Bluetooth Low Energy Devicesのサンプルコードを派生させて、ファイルの送受信をしたいと考えています。
サンプルコードをそのまま実行するとペリフェラルに書かれたテキストがセントラル側に転送されるようになっています。
ペリフェラルとセントラルが接続されたらペリフェラルから画像、音声、テキストファイルの様なものを転送したいのですが、よくわかりません。例えば画像を送信したいときはどうすれば良いのでしょうか。
発生している問題
接続が確認されたらセントラル側から決められた音が鳴る様にすることはできたのですが、ペリフェラル側からファイルを転送するとなるとよくわかりません。
該当のソースコード
PeripheralViewController
1 2import UIKit 3import CoreBluetooth 4import os 5 6class PeripheralViewController: UIViewController { 7 8 @IBOutlet var textView: UITextView! 9 @IBOutlet var advertisingSwitch: UISwitch! 10 11 var peripheralManager: CBPeripheralManager! 12 13 var transferCharacteristic: CBMutableCharacteristic? 14 var connectedCentral: CBCentral? 15 var dataToSend = Data() 16 var sendDataIndex: Int = 0 17 18 // MARK: - View Lifecycle 19 20 override func viewDidLoad() { 21 peripheralManager = CBPeripheralManager(delegate: self, queue: nil, options: [CBPeripheralManagerOptionShowPowerAlertKey: true]) 22 super.viewDidLoad() 23 24 } 25 26 override func viewWillDisappear(_ animated: Bool) { 27 // Don't keep advertising going while we're not showing. 28 peripheralManager.stopAdvertising() 29 30 super.viewWillDisappear(animated) 31 } 32 33 @IBAction func switchChanged(_ sender: Any) { 34 // All we advertise is our service's UUID. 35 if advertisingSwitch.isOn { 36 peripheralManager.startAdvertising([CBAdvertisementDataServiceUUIDsKey: [TransferService.serviceUUID]]) 37 } else { 38 peripheralManager.stopAdvertising() 39 } 40 } 41 42 static var sendingEOM = false 43 44 private func sendData() { 45 46 guard let transferCharacteristic = transferCharacteristic else { 47 return 48 } 49 50 // First up, check if we're meant to be sending an EOM 51 if PeripheralViewController.sendingEOM { 52 // send it 53 let didSend = peripheralManager.updateValue("EOM".data(using: .utf8)!, for: transferCharacteristic, onSubscribedCentrals: nil) 54 // Did it send? 55 if didSend { 56 // It did, so mark it as sent 57 PeripheralViewController.sendingEOM = false 58 os_log("Sent: EOM") 59 } 60 // It didn't send, so we'll exit and wait for peripheralManagerIsReadyToUpdateSubscribers to call sendData again 61 return 62 } 63 64 if sendDataIndex >= dataToSend.count { 65 // No data left. Do nothing 66 return 67 } 68 69 var didSend = true 70 while didSend { 71 72 var amountToSend = dataToSend.count - sendDataIndex 73 if let mtu = connectedCentral?.maximumUpdateValueLength { 74 amountToSend = min(amountToSend, mtu) 75 } 76 77 let chunk = dataToSend.subdata(in: sendDataIndex..<(sendDataIndex + amountToSend)) 78 79 // Send it 80 didSend = peripheralManager.updateValue(chunk, for: transferCharacteristic, onSubscribedCentrals: nil) 81 82 if !didSend { 83 return 84 } 85 86 let stringFromData = String(data: chunk, encoding: .utf8) 87 os_log("Sent %d bytes: %s", chunk.count, String(describing: stringFromData)) 88 89 sendDataIndex += amountToSend 90 // Was it the last one? 91 if sendDataIndex >= dataToSend.count { 92 93 PeripheralViewController.sendingEOM = true 94 95 //Send it 96 let eomSent = peripheralManager.updateValue("EOM".data(using: .utf8)!, 97 for: transferCharacteristic, onSubscribedCentrals: nil) 98 99 if eomSent { 100 // It sent; we're all done 101 PeripheralViewController.sendingEOM = false 102 os_log("Sent: EOM") 103 } 104 return 105 } 106 } 107 } 108 109 private func setupPeripheral() { 110 111 let transferCharacteristic = CBMutableCharacteristic(type: TransferService.characteristicUUID, 112 properties: [.notify, .writeWithoutResponse], 113 value: nil, 114 permissions: [.readable, .writeable]) 115 116 // Create a service from the characteristic. 117 let transferService = CBMutableService(type: TransferService.serviceUUID, primary: true) 118 119 // Add the characteristic to the service. 120 transferService.characteristics = [transferCharacteristic] 121 122 // And add it to the peripheral manager. 123 peripheralManager.add(transferService) 124 125 // Save the characteristic for later. 126 self.transferCharacteristic = transferCharacteristic 127 128 } 129} 130 131extension PeripheralViewController: CBPeripheralManagerDelegate { 132 133 internal func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { 134 135 advertisingSwitch.isEnabled = peripheral.state == .poweredOn 136 137 switch peripheral.state { 138 case .poweredOn: 139 // ... so start working with the peripheral 140 os_log("CBManager is powered on") 141 setupPeripheral() 142 case .poweredOff: 143 os_log("CBManager is not powered on") 144 // In a real app, you'd deal with all the states accordingly 145 return 146 case .resetting: 147 os_log("CBManager is resetting") 148 // In a real app, you'd deal with all the states accordingly 149 return 150 case .unauthorized: 151 // In a real app, you'd deal with all the states accordingly 152 if #available(iOS 13.0, *) { 153 switch peripheral.authorization { 154 case .denied: 155 os_log("You are not authorized to use Bluetooth") 156 case .restricted: 157 os_log("Bluetooth is restricted") 158 default: 159 os_log("Unexpected authorization") 160 } 161 } else { 162 // Fallback on earlier versions 163 } 164 return 165 case .unknown: 166 os_log("CBManager state is unknown") 167 // In a real app, you'd deal with all the states accordingly 168 return 169 case .unsupported: 170 os_log("Bluetooth is not supported on this device") 171 // In a real app, you'd deal with all the states accordingly 172 return 173 @unknown default: 174 os_log("A previously unknown peripheral manager state occurred") 175 // In a real app, you'd deal with yet unknown cases that might occur in the future 176 return 177 } 178 } 179 180 func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) { 181 os_log("Central subscribed to characteristic") 182 183 // Get the data 184 dataToSend = textView.text.data(using: .utf8)! 185 186 // Reset the index 187 sendDataIndex = 0 188 189 // save central 190 connectedCentral = central 191 192 // Start sending 193 sendData() 194 } 195 196 func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didUnsubscribeFrom characteristic: CBCharacteristic) { 197 os_log("Central unsubscribed from characteristic") 198 connectedCentral = nil 199 } 200 201 func peripheralManagerIsReady(toUpdateSubscribers peripheral: CBPeripheralManager) { 202 // Start sending again 203 sendData() 204 } 205 206 func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) { 207 for aRequest in requests { 208 guard let requestValue = aRequest.value, 209 let stringFromData = String(data: requestValue, encoding: .utf8) else { 210 continue 211 } 212 213 os_log("Received write request of %d bytes: %s", requestValue.count, stringFromData) 214 self.textView.text = stringFromData 215 } 216 } 217} 218 219extension PeripheralViewController: UITextViewDelegate { 220 // implementations of the UITextViewDelegate methods 221 222 func textViewDidChange(_ textView: UITextView) { 223 // If we're already advertising, stop 224 if advertisingSwitch.isOn { 225 advertisingSwitch.isOn = false 226 peripheralManager.stopAdvertising() 227 } 228 } 229 230 func textViewDidBeginEditing(_ textView: UITextView) { 231 // We need to add this manually so we have a way to dismiss the keyboard 232 let rightButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(dismissKeyboard)) 233 navigationItem.rightBarButtonItem = rightButton 234 } 235 236 /* 237 * Finishes the editing 238 */ 239 @objc 240 func dismissKeyboard() { 241 textView.resignFirstResponder() 242 navigationItem.rightBarButtonItem = nil 243 } 244 245} 246 247 248
あなたの回答
tips
プレビュー