Help us understand the problem. What is going on with this article?

BLEのペリフェラルを今更実装してみた(iOS編)

More than 5 years have passed since last update.

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を追加

add_corebluetooth_framework.png

(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()
    }
}

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away