0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Androidで CompanionDeviceManager でアプリ非起動時の BLE バックグラウンド同期を実装して詰まったこと

0
Posted at

はじめに

Bluetooth(以降BLE)周辺機器と連携するアプリで、「デバイスが近くに来たら自動でデータ同期したい」となったので、フォアグラウンドサービスを常時起動するのはバッテリー消費の観点から避けたく、Android 13 で追加された CompanionDeviceManager(以降CDM)の presence observation を採用したので今回はその時のメモ的な記事です。

CompanionDeviceManagerの仕組み

CDM にデバイスを登録(association)して startObservingDevicePresence を呼ぶと、OS がデバイスの BLE 信号を代わりに監視してくれます。デバイスが BLE 範囲に入るCompanionDeviceService が起動してコールバックが届きます。アプリのプロセスがキルされた状態でも動くのが最大のポイントです。

 // association 作成後に presence 監視を開始                                      
 manager.startObservingDevicePresence(deviceMacAddress)

詰まったこと1

Android 16 で super を呼ぶと二重発火する

Android13〜15 は onDeviceAppeared / onDeviceDisappeared が呼ばれますが、Android 16 から onDevicePresenceEvent が追加されました。ここで
super.onDevicePresenceEvent(event) を呼ぶと、deprecated コールバックへ再ディスパッチするため両方のメソッドが呼ばれて二重処理になります。

  @RequiresApi(Build.VERSION_CODES.BAKLAVA)  
  override fun onDevicePresenceEvent(event: DevicePresenceEvent) { 
  // super は意図的に呼ばない
  val address = resolveAssociationAddress(event.associationId)
  when (event.event) {
    DevicePresenceEvent.EVENT_BLE_APPEARED -> handleDeviceAppeared(address)          DevicePresenceEvent.EVENT_BLE_DISAPPEARED -> handleDeviceDisappeared(address)
    }
  } 

また Android 16 では startObservingDevicePresence(String) も deprecated になり、ObservingDevicePresenceRequest を使う新しい API に変わっています。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {                                                                                                        
   manager.startObservingDevicePresence(                                                                                                                            
       ObservingDevicePresenceRequest.Builder().setAssociationId(association.id).build()
   )                                                                                                                                                                
} else {                                                                                                                                                           
   @Suppress("DEPRECATION")            
   manager.startObservingDevicePresence(deviceMacAddress)
} 

詰まったこと2

プロセス再生成後に監視が消える

ペアリング時に startObservingDevicePresence を呼んだだけでは、アプリプロセスが再生成されたあと監視が失われていました。Application.onCreate で既存の association に対して監視を再登録する必要があります。

  // Application.onCreate で呼ぶ                                                                                                                                       
  fun reobserveAssociatedDevices() {
      if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return                                                                                                 
      manager.myAssociations.forEach { association ->                                                                                                                
          startObservingDevicePresence(manager, association)
      }                                       
  }    

この処理を入れるまで、アプリを一度強制終了するとデバイスが来ても同期が走らない問題に悩まされていました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?