¶ Как сканировать BLE на Android + известные проблемы
¶ JELLY_BEAN_MR1 (Android 4.2) и ниже
- Используйте старый адаптер bt, устарел в новых версиях Android
- Используйте старый метод сканирования, устарел в новых версиях Android
- Адаптер Bluetooth должен перезапускаться каждые 3 секунды из-за переполнения стека bt
- Работа в фоновом режиме без ограничений
¶ Начиная с JELLY_BEAN_MR2 (Android 4.2) до Android 7.1
- Используйте старый адаптер bt, устарел в новых версиях Android
- Используйте старый метод сканирования, устарел в новых версиях Android
- Адаптер Bluetooth должен перезапускаться каждые 3 секунды из-за переполнения стека bt
- Фоновая служба должна периодически перезапускать сканер bt
Задача |
4.3-4.4.x |
5.0-7.x |
8.0 |
Поддержка длительных сканирующих служб |
ДА |
ДА |
НЕТ |
Поддержка сканирования через JobScheduler |
НЕТ |
ДА |
ДА |
Поддержка фильтров сканирования Bluetooth |
НЕТ |
ДА |
ДА |
Отправка обнаружений Bluetooth в виде интентов |
НЕТ |
НЕТ |
ДА |
Обнаружение возможно после перезагрузки |
ДА |
ДА |
ДА |
Обнаружение возможно после остановки диспетчера задач |
ДА |
ДА |
ДА |
Время обнаружения первого маяка (в секундах) |
300 |
5 |
5 |
Время обнаружения второго маяка (в секундах) |
300 |
300 |
450 |
Время обнаружения исчезновения маяка (в секундах) |
300 |
300 |
450 |
Время обнаружения после остановки (в секундах) |
300 |
5 |
450 |
Максимальное время обнаружения маяка (в секундах) |
300 |
300 |
1500 |
¶ Android 8
- Alarm manager больше не поддерживается для сканирования bt в фоновом режиме
- Доступно новое API для сканирования
ScanSettings settings = (new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)).build();
List<ScanFilter> filters = getScanFilters();
BluetoothManager bluetoothManager =
(BluetoothManager) mContext.getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
Intent intent = new Intent(mContext, NavigineBroadcastReceiver.class);
intent.putExtra("navigine-ble-intent", true);
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
bluetoothAdapter.getBluetoothLeScanner().startScan(filters, settings, pendingIntent);
- Результаты сканирования могут быть получены следующим образом
public class NavigineBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int bleCallbackType = intent.getIntExtra(BluetoothLeScanner.EXTRA_CALLBACK_TYPE, -1);
if (bleCallbackType != -1) {
Log.d(TAG, "Тип обратного вызова пассивного фонового сканирования: " + bleCallbackType);
ArrayList<ScanResult> scanResults = intent.getParcelableArrayListExtra(
BluetoothLeScanner.EXTRA_LIST_SCAN_RESULT);
}
}
}
- ОС завершит приложение в течение 15 минут после первого обнаружения, поэтому, если нам нужно продолжать искать второй маяк в окрестности и он не появляется в течение 16 минут, наше приложение больше не будет работать.
- Мы можем настроить JobScheduler для периодического поиска маяков вокруг нас и передачи информации о них в наше приложение. (В Android 8 периодические задания ограничены максимальным интервалом в 15 минут (900 секунд), что означает, что может потребоваться столько времени для обнаружения нового маяка или обнаружения исчезновения маяка, хотя среднее время обнаружения обычно составляет половину этого времени (450 секунд))
¶ Android 8+
- Версии Android 8+ ограничивают работу служб в фоновом режиме только на 10 минут после выхода приложения из фокуса. Это блокирует обнаружение маяков в фоновом режиме.
- Использование JobScheduler для выполнения сканирования, но они ограничены максимальным интервалом в 15 минут
- Частое запускание/остановка сканирования может вызвать переполнение стека bt
- Использование Foreground Service (Foreground service отличается от обычных фоновых служб Android тем, что показывает постоянное уведомление с значком вашего приложения и настраиваемым текстом во время выполнения сканирования маяков, чтобы пользователи знали, что сканирование происходит)
- Сканирование с использованием foreground service возможно только с настройками ScanSettings.SCAN_MODE_LOW_POWER (примерно: сканирование 0,5 секунды, ожидание 5 секунд).
¶ Android 10
- Обычно для работы обнаружения маяков, когда ваше приложение невидимо, требуется разрешение ACCESS_BACKGROUND_LOCATION. Однако возможно проводить сканирование только с разрешением на передний план и работой в foreground service, если вы добавите android:foregroundServiceType="location" в объявление foreground service в манифесте.
- Некоторые производители телефонов модифицируют ограничения Android, добавляя свой собственный код для энергосбережения, который уничтожает фоновые приложения, включая foreground service. Известно, что на это влияют устройства Huawei, Xiaomi, Redmi и OnePlus. Подробнее читайте здесь.