[Android 8.0(Oreo)]PendingIntent에서 BLE 스캔 결과 받기

머리



Android 8.0(Oreo)에서 BLE 스캔을 위한 새로운 메소드가 추가되었습니다.
Nougat까지는 콜백으로 스캔 결과를 받는 스타일이었지만, 추가된 메소드에서는 PendingIntent로 결과를 받을 수 있게 됩니다.

바로 움직여 어떤 느낌인지 느낌을 잡아 보았습니다.

환경


  • Nexus5X(Android 8.0)
  • Android Sutdio 3.0.1
  • Kotlin 1.2.0

  • Android 7.1.2(Nougat)까지의 BLE 스캔



    Nougat까지 스캔 결과는 콜백으로받는 스타일이었습니다.
    이것이 앱의 프로세스가 살아있는 동안에만받을 수 있기 때문에,
    BLE의 스캔을 상시 계속하는 타입의 앱에서는, 조금 작은 세공을 넣어 줄 필요가 있었습니다.
    예를 들어 포그라운드 서비스를 사용하여 상주하거나 JobScheduler나 AlarmManager에서 주기적으로 서비스를 시작하여 BLE 스캔을 해야 했습니다.

    덧붙여서 여기가 Nougat 이전의 BLE 스캔용의 메소드입니다.


    Android 8.0 (Oreo) 이상에서 BLE 스캔



    그리고 Oreo에서 추가된 BLE 스캔을 위한 방법이 여기에 있습니다.

    콜백을 설정하는 대신 PendingIntet에서 스캔 결과를 받을 수 있습니다.
    스캔 시작 성공 및 실패는 메소드의 반환 값으로 반환되도록 변경되었습니다.

    1. PendingIntent 생성



    먼저 PendingIntent를 생성합니다.
    이번에는 BLE 스캔 결과를 받기위한 BroadcastReceiver를 지정하려고했습니다.
    requestCode는 임의의 고유한 값을 지정해 두면 OK입니다(0을 지정하면 Intent가 통지되지 않으므로 주의)
    fun createBleScanPendingIntent(context: Context): PendingIntent {
        val requestCode = 222
        val intent = Intent(context, BleScanReceiver::class.java)
        return PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT)
    }
    

    2. BLE 스캔 시작



    BLE 스캔 설정, 스캔 필터에 대해서는 Nougat 이전의 지정 방법과 같습니다. null 지정도 가능.
    스캔 시작 메소드에 콜백 대신 PendingIntent를 지정하면 스캔이 시작됩니다.
    fun startBleScan(context: Context) {
        // BLE Scan設定
        val scanSettings = ScanSettings.Builder()
                .setScanMode(ScanSettings.SCAN_MODE_BALANCED)
                .build()
    
        // BLE Scanフィルタ
        val scanFilters = listOf(ScanFilter.Builder().setDeviceAddress("XX:XX:XX:XX:XX:XX").build())
    
        // PendingIntent
        val pendingIntent = createBleScanPendingIntent(context)
    
        // BLEスキャン開始
        bluetoothAdapter?.bluetoothLeScanner?.startScan(scanFilters, scanSettings, pendingIntent).let {
            if(it != 0) {
                // BLEスキャン失敗
            }
        }
    }
    

    조금 신경이 쓰이는 것이 BLE 스캔 실패의 경우입니다. 역시 Bluetooth를 OFF/ON 할 수밖에 없는지 신경이 쓰이는 곳입니다.

    3. BLE 스캔 결과 수신



    BroadcastReceiver는 오류 코드, 콜백 유형 및 BLE 스캔 결과를 알립니다.
    Oreo에서는 암시적 Intent를 받는 BroadcastReceiver를 AndroidManifest.xml에 지정할 수 없다는 제한이 있습니다.
    이것은 명시적인 Intent이므로 AndroidManifest.xml에 지정할 수 있습니다.
    class BleScanReceiver : BroadcastReceiver() {
    
        override fun onReceive(context: Context?, intent: Intent?) {
            // Error code
            val error = intent.getIntExtra(BluetoothLeScanner.EXTRA_ERROR_CODE, -1)
            if (error != -1) {
                // BLEスキャン失敗
                Log.d(TAG, "BLE Scan error : $error")
                return
            }
    
            // Callback type
            val callbackType = intent.getIntExtra(BluetoothLeScanner.EXTRA_CALLBACK_TYPE, -1)
            Log.d(TAG, "Callback type : $callbackType")
    
            // Scan results
            val scanResults: ArrayList<ScanResult> = intent.getParcelableArrayListExtra(BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT)
            for (scanResult in scanResults) {
                // ゴニョゴニョ
                scanResult.device.name?.let {
                    Log.d(TAG, "Scan reuslt : $it")
                }
            }
    
            // BLEスキャン停止
            stopBleScan(context)
        }
    }
    

    4. BLE 스캔 중지



    스캔을 정지할 때는 스캔을 시작했을 때와 같은 내용의 PendingIntent를 지정해 줍니다.
    fun stopBleScan(context: Context) {
        // BLEスキャン開始した時と同じ内容のPendingIntentを使う
        val pendingIntent = createBleScanPendingIntent(context)
    
        // BLEスキャン停止
        bluetoothAdapter?.bluetoothLeScanner?.stopScan(pendingIntent)
    }
    

    요약



    Nougat 이전과 Oreo에서 그다지 큰 차이는 없었고, PendingIntent에서 BLE 스캔 결과를 받을 수 있다는 점이 바뀌었다.
    다만, PendingIntent가 된 것에 의해 앱이 상주해 BLE 스캔을 계속할 필요가 없어진 것이 큰 차이입니다.

    참고



    htps : //로 ゔぇぺぺr. 안 d로이 d. 코 m/레후오렌세/안 d로이 d/bぅ에오 th/ぇ/Bぅ에토 thぇS칸에 r. HTML
    htps : //에서 ゔぇぺぺr. 안 d로이 d. 코 m/아보 t/ゔぇr 시온 s/오레오/바 ckg 로우 d. HTML

    좋은 웹페이지 즐겨찾기