読者です 読者をやめる 読者になる 読者になる

【iOS】バックグラウンドでBluetoothのコネクションを維持する

iOSデバイスでのBluetooth通信は基本アプリが画面内に表示されている'フォアグラウンド'の時のみ有効です。
今回はアプリがバックグラウンドに隠れた間でも、Bluetooth通信を可能にする裏技的な(?)tipsを紹介します。

バックグラウンドで実行可能な処理

まずiOSでバックグラウンド実行が可能なものを見てみましょう。
iOSでは、バックグラウンドで行える処理が以下のものに限られています。
Apple iOS App Programming Guide

  • 音楽の再生
  • 位置情報の取得
  • VoIP
  • Newsstandを使用するアプリ
  • 外部アクセサリから定期的に情報をアップデートするアプリ

このような、バックグラウンドでの動作が重要なサービスに限り許されています。

iOS Bluetoothフレームワークの種類

iOSが提供するBluetoothフレームワークには大きく分けて2種類あります。

名称 使用可能なデバイス バックグラウンド通信
Game Kit Bluetoothが使用可能なiPhone全て ×
Core Bluetooth iPhone4S以降

CoreBluetoothはBluetooth LE(Low Energy)に対応した外部機器との通信のみに使われます。
今回のターゲットはGame Kitフレームワークでのバックグラウンド通信です。

Bluetoothのコネクションを維持する方法

ではバックグラウンド通信を可能にするにはどうしたらいいのでしょうか。
実は、音楽をバックグラウンドで再生している間は、Bluetoothの通信が可能となっています。

以下、無音の音楽を永遠と再生し続けるサンプルコードです。

    // オーディオデータフォーマットを表す構造体を作成
    AudioStreamBasicDescription dummyASBD;
    dummyASBD.mSampleRate = 44100.0;
    dummyASBD.mFormatID = kAudioFormatLinearPCM;
    dummyASBD.mFormatFlags = kAudioFormatFlagsCanonical;
    dummyASBD.mBytesPerPacket = 4;
    dummyASBD.mFramesPerPacket = 1;
    dummyASBD.mBytesPerFrame = 4;
    dummyASBD.mChannelsPerFrame = 2;
    dummyASBD.mBitsPerChannel = 16;
    dummyASBD.mReserved = 0;
    
    OSStatus status;
    // AudioQueueの作成
    status = AudioQueueNewOutput(&dummyASBD,
                                 dummyAudioQueueCallBack,
                                 self,
                                 NULL,
                                 NULL,
                                 0,
                                 &dummyAudioQueue);
    if (status) {
        NSLog("error @AudioQueueNewOutput");
    }
    
    // 再生
    status = AudioQueueStart(dummyAudioQueue, NULL);
    if (status) {
        NSLog(@"error @AudioQueueStart");
    }

実際にバックグラウンドで試すときは、アプリのinfo.plistのバックグラウンドモードの項目にAudio Playが設定されていることを確かめてください。

<key>UIBackgroundModes</key> 
<array>
    <string>audio</string>
</array>

この状態であれば、GKSessionクラスのsendDataToAllPeers:withDataMode:error:メソッドや、receiveData:fromPeer:inSession:context:メソッドでデータの送受信が可能となっています。

最後に

もしかすると、音楽の再生以外にもバックグラウンド処理が許されているもの(例えばVoIPなど)でも同じことが可能かもしれません。
尚、この方法はAppleのガイドラインには書かれていないため、明らかに不推奨な方法だと思われます。 バックグラウンドで通信することに意義があるサービスのみに適応するよう心がけてください。