BLEのペリフェラルを今更実装してみた(iOS編)
準備
(1) BLE用のUUIDを作成する
ターミナルを起動して以下コマンドを入力
$ uuidgen
すると以下のようなUUIDが自動生成されるのでコピーしておく
71DA3FD1-7E10-41C1-B16F-4430B506CDE7
CCUUIDとして定義
BLEDefine.swift
/** BLEで用いるサービス用のUUID */
let BLEServiceUUID = CBUUID(string:"71DA3FD1-7E10-41C1-B16F-4430B506CDE7")
/** BLEで用いるキャラクタリスティック用のUUID */
let BLECharacteristicUUID = CBUUID(string:"E977DFF0-36D0-4B3B-89D5-575AAE17B6B3")
(2) CoreBluetooth Frameworkを追加
(3) CoreBluetoothをインポート
使うファイル内の先頭辺りでインポート文を書く
import CoreBluetooth
CoreBluetoothのEnum値
ログを出すときに楽なので name プロパティを追加しておきます
BLEEnumExtension.swift
extension CBCentralManagerState
{
var name : NSString {
get{
var enumName = "CBCentralManagerState"
var valueName = ""
switch self {
case .PoweredOff:
valueName = enumName + "PoweredOff"
case .PoweredOn:
valueName = enumName + "PoweredOn"
case .Resetting:
valueName = enumName + "Resetting"
case .Unauthorized:
valueName = enumName + "Unauthorized"
case .Unknown:
valueName = enumName + "Unknown"
case .Unsupported:
valueName = enumName + "Unsupported"
}
return valueName
}
}
}
extension CBPeripheralState
{
var name : NSString {
get{
var enumName = "CBPeripheralState"
var valueName = ""
switch self {
case .Connected:
valueName = enumName + "Connected"
case .Connecting:
valueName = enumName + "Connecting"
case .Disconnected:
valueName = enumName + "Disconnected"
}
return valueName
}
}
}
extension CBPeripheralManagerState
{
var name : NSString {
get{
var enumName = "CBPeripheralManagerState"
var valueName = ""
switch self {
case .PoweredOff:
valueName = enumName + "PoweredOff"
case .PoweredOn:
valueName = enumName + "PoweredOn"
case .Resetting:
valueName = enumName + "Resetting"
case .Unauthorized:
valueName = enumName + "Unauthorized"
case .Unknown:
valueName = enumName + "Unknown"
case .Unsupported:
valueName = enumName + "Unsupported"
}
return valueName
}
}
}
実装
BLEPeripheralManager.swift
class BLEPeripheralManager : NSObject {
// MARK: - Property
/** シングルトンインスタンス */
class var sharedManager : BLEPeripheralManager {
struct Static {
static let instance : BLEPeripheralManager = BLEPeripheralManager()
}
return Static.instance
}
/** BLEのペリフェラルマネージャー、BLE発信側としての機能をサポートする */
private var peripheralManager : CBPeripheralManager?
/** 発信するキャラクタリスティック */
private var characteristic = CBMutableCharacteristic(
type:BLECharacteristicUUID,
properties:CBCharacteristicProperties.Notify,
value:nil,
permissions:CBAttributePermissions.Readable)
/** 発信するデータ */
var dataToSend = NSData()
/** 発信するデータのインデックス */
private var sendDataIndex = 0
/** フラグ値 */
private var sendingEOM : Bool = false
// MARK: - Public
/** BLEのペリフェラルを使用開始できる状態にセットアップ */
func setup()
{
self.peripheralManager = CBPeripheralManager(delegate:self, queue:nil)
}
/** BLEのペリフェラルを使用できない状態にする */
func teardown()
{
self.peripheralManager = nil
}
/** アドバタイズを開始 */
func startAdvertising()
{
self.peripheralManager?.startAdvertising([CBAdvertisementDataServiceUUIDsKey:[BLEServiceUUID]])
}
/** アドバタイズを停止 */
func stopAdvertising()
{
self.peripheralManager?.stopAdvertising()
}
// MARK: Private
/** データを送信する */
func sendData()
{
if self.sendingEOM {
var data = "EOM".dataUsingEncoding(NSUTF8StringEncoding)
var didSend : Bool = self.peripheralManager!.updateValue(
data,
forCharacteristic:self.characteristic,
onSubscribedCentrals: nil)
if didSend {
self.sendingEOM = false
return
}
}
var didSend = true
while didSend {
var amountToSend = self.dataToSend.length - self.sendDataIndex
if amountToSend > 20 {
amountToSend = 20
}
var chunk = NSData(bytes:self.dataToSend.bytes+self.sendDataIndex, length: amountToSend)
didSend = self.peripheralManager!.updateValue(
chunk,
forCharacteristic:self.characteristic,
onSubscribedCentrals: nil)
if !didSend {
return
}
var stringFromData = NSString(data:chunk, encoding:NSUTF8StringEncoding)
self.sendDataIndex += amountToSend
if self.sendDataIndex >= self.dataToSend.length {
self.sendingEOM = false
let eomSent : Bool = self.peripheralManager!.updateValue(
"EOM".dataUsingEncoding(NSUTF8StringEncoding),
forCharacteristic:self.characteristic,
onSubscribedCentrals: nil)
if eomSent {
sendingEOM = false
}
return
}
}
}
}
// MARK: - CBPeripheralManagerDelegate
extension BLEPeripheralManager : CBPeripheralManagerDelegate
{
func peripheralManager(
peripheral: CBPeripheralManager!,
central: CBCentral!,
didSubscribeToCharacteristic characteristic: CBCharacteristic!)
{
self.sendDataIndex = 0
self.sendData()
}
func peripheralManager(
peripheral: CBPeripheralManager!,
central: CBCentral!,
didUnsubscribeFromCharacteristic characteristic: CBCharacteristic!)
{
println("didUnsubscribeFromCharacteristic")
}
func peripheralManager(
peripheral: CBPeripheralManager!,
didAddService service: CBService!,
error: NSError!)
{
if error == nil {
println("正常にサービスの追加が完了しました")
} else {
println("サービスの追加に失敗しました")
}
}
func peripheralManager(
peripheral: CBPeripheralManager!,
didReceiveReadRequest request: CBATTRequest!)
{
println("didReceiveReadRequest")
}
func peripheralManager(
peripheral: CBPeripheralManager!,
didReceiveWriteRequests requests: [AnyObject]!)
{
println("didReceiveWriteRequests")
}
func peripheralManager(
peripheral: CBPeripheralManager!,
willRestoreState dict: [NSObject : AnyObject]!)
{
println("willRestoreState")
}
func peripheralManagerDidStartAdvertising(
peripheral: CBPeripheralManager!,
error: NSError!)
{
if error == nil {
println("PeripheralがAdvertisingを開始しました")
} else {
println("PeripheralがAdvertisingの開始に失敗しました\(error)")
}
}
func peripheralManagerDidUpdateState(peripheral: CBPeripheralManager!)
{
println("PeripheralのStateが変更されました(現在のState:\(peripheral.state.name))")
if peripheral.state != CBPeripheralManagerState.PoweredOn {
println("異常なStateのため処理を終了します")
return;
}
var service = CBMutableService(type:BLEServiceUUID, primary:true)
service.characteristics = [self.characteristic]
self.peripheralManager?.addService(service)
}
func peripheralManagerIsReadyToUpdateSubscribers(peripheral: CBPeripheralManager!)
{
self.sendData()
}
}