【Swift/Core Bluetooth】バックグラウンドモードの有効化!処理を継続させる

この記事からわかること

  • Swift × Core BluetoothBluetooth接続アプリ実装方法
  • バックグラウンドモードとは?
  • セントラル側で処理継続させるには?
  • 動作する時間は?

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

バックグラウンドでもBLE機能の処理を継続させる方法

Swiftでバックグラウンドに移行しても処理を継続させる方法beginBackgroundTaskを使用した方法などいくつかありますが、Bluetooth接続を行うアプリではもっと簡単にバックグラウンド操作が可能になっています。

今回紹介する方法はセントラル側がペリフェラルからデータを取得した後の処理をバックグラウンドでも継続させる方法です。

バックグラウンドモードの設定方法

Bluetooth機能をバックグラウンドでも有効にするためには「Signing & Capabilities」から「+Capability」>「Background Modes」を追加します。

Swift/Core Bluetooth】バックグラウンドモードの有効化!処理を継続させる

追加できたら「Uses Bluetooth LE accessories」にチェックを入れるだけです。

Swift/Core Bluetooth】バックグラウンドモードの有効化!処理を継続させる

これでバックグラウンドでも操作が可能になります。

検証してみる

実際にバックグラウンドモードを有効にした際の違いを確認してみます。Bluetooth機能の実装方法などについては以下の記事を参考にしてください。

ReadやNotifyなどペリフェラルからデータが送信され、セントラル側で受け取るためのperipheral(_:, didUpdateValueFor characteristic:, error:)デリゲートメソッドの中で動きを確認していきます。分かりやすいように実行しているアプリの状態を取得して出力するようにしておきました。


// ReadやNotifyのデータを受信する
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    print("ペリフェラルから値を取得しました。")

    let state = UIApplication.shared.applicationState
    switch state {
    case .active:
        print("Active")
    case .inactive:
        print("Inactive")
    case .background:
        print("Background")
    @unknown    default:
        print("unknown")
    }
}

ペリフェラル側の実装にはNotifyが定期的に送信されるようにタイマーを使用して3秒ごとに発火するようにしておきます。


var timerPublisher: AnyCancellable?
  
// Notifyを3秒ごとに送信
public func sendNotify() {
    timerPublisher = Timer.publish(every: 3, on: .current, in: .common)
        .autoconnect()
        .receive(on: DispatchQueue(label: "subthread", qos: .background))
        .sink {[weak self] _ in
            guard let self = self else { return }
            if let data = "Notify".data(using: .utf8) {
                self.notifyCharacteristic.value = data
                self.peripheralManager.updateValue(data, for: notifyCharacteristic, onSubscribedCentrals: nil)
            }
        }
}

これでコネクトした後にセントラル側がNotifyを観測した状態でアプリをバックグラウンドに移行させても問題なく動作することが確認できました。

ペリフェラルから値を取得しました。
Background

バックグラウンドでの動作時間

バックグラウンドで処理を実行できる時間はペリフェラルからデータが送られ続ける限り、半永久的に動作できそうな感じでした。

Notifyを一回だけ送信し、バックグラウンドで受けた場合にタイマーを利用してどこまで処理が継続されるか検証してみましたが、400秒を超えても出力されていたので、こちらも半永久的なのでしょうか?

// ReadやNotifyのデータを受信する
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    print("ペリフェラルから値を取得しました。\n")

    var count = 0
    timerPublisher = Timer.publish(every: 1, on: .current, in: .common)
            .autoconnect()
            .receive(on: DispatchQueue(label: "subthread", qos: .background))
            .sink { _ in
                count += 1
                print(count)
            }
}

今回の検証はバックグラウンドモードが無効になっている場合はバックグラウンド状態では以下が出力されることもなく、またタイマーのカウントが始まることもありませんでした。

ペリフェラルから値を取得しました。
Background

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index