Трансляция не запускается при использовании bluetoothLEScanner (). StartScan

Я пытаюсь разбудить свое приложение, когда устройство входит в область маяков с определенным UUID.

До сих пор я пробовал использовать собственный BluetoothAdapter.getBluetoothLeScanner, предоставляя PendingIntent для запуска радиоприемника.

Я также попробовал RxBleClient, замечательную библиотеку, которая работает при регулярном обнаружении.

Я попробовал библиотеку AltBeacon, которая также является очень полной и блестящей библиотекой.

Еще пробовал играть в сервисы Nearby Apis.

Но все провалилось. Все они могут регулярно сканировать маяки, но, в основном, при попытке зарегистрироваться и позволить устройству сканировать, находясь в режиме bg. Трансляция никогда не запускается.

Я также пробовал все 4 при использовании службы переднего плана. Это тоже не помогло. Я также упомяну, что все это делается на Android 8. Я просмотрел код в обеих библиотеках, и в конечном итоге они оба используют один и тот же вызов функции из собственного bluetoothadapter. Итак, я предполагаю, что если это не удастся, все остальное тоже потерпит неудачу. Я также упомяну, что при предоставлении функции startScan CallBack вместо PendingIntent, обратный вызов постоянно запускается для всех просканированных устройств BT. Если я добавлю ScanFilter для фильтрации только моего UUID, это не сработает. Что мне не хватает?

Кстати, когда я реализовал это на iOS, он работал безупречно. Приложение просыпается, как если бы я использовал триггер входа / выхода Geofence.

Почему это не работает в Android? Есть предположения?

РЕДАКТИРОВАТЬ: вот как я использовал код из библиотеки AltBeacon. По сути, это копипаст из учебника DOCS. Единственная разница в том, что я инкапсулировал его в отдельный класс:

public void init(AppCompatActivity context) {
    if (isRegistered) {
        return;
    }

    BluetoothManager bluetoothManager = (BluetoothManager) context.getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE);
    if (bluetoothManager != null) {
        bluetoothAdapter = bluetoothManager.getAdapter();
        if (!bluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            context.startActivityForResult(enableBtIntent, 1002);
        } else {
            register(context);
        }
    }
}

public void register(AppCompatActivity context) {

    if (isRegistered) {
        return;
    }

    executorService.execute(new Runnable() {
        @Override
        public void run() {
            Region region = new Region("com.sample.WakeOnDiscovery", Identifier.parse("E2C56DB5-DFFB-48D2-B060-D0F5A71096E0"), Identifier.fromInt(11180), null);
            bootstrapRegion = new RegionBootstrap(new BootstrapNotifier() {
                @Override
                public Context getApplicationContext() {
                    return Application.getContextFromApplicationClass();
                }

                @Override
                public void didEnterRegion(Region region) {
                    Logger.log(TAG, "didEnterRegion: " + region.toString());
                }

                @Override
                public void didExitRegion(Region region) {
                    Logger.log(TAG, "didExitRegion: " + region.toString());
                }

                @Override
                public void didDetermineStateForRegion(int i, Region region) {
                    Logger.log(TAG, "didDetermineStateForRegion: " + region.toString() + "|" + i);
                }
            }, region);
        }
    });

    isRegistered = true;
}

Это когда я пытаюсь сканировать этот конкретный UUID и основной int (и без основного int). Как только я думаю, срабатывает только didDetermineStateForRegion. С int i = 0 или 1.

Что касается UUID, я пробовал 2 разных UUID. Первый - это то, что я создаю в образце приложения, написанном на IOS. Приложение ios позиционирует себя как маяк. Я вижу это в другом приложении, которое использует обычную функцию обнаружения. Но onEnterRegion не срабатывает.

Я также попробовал UUID от устройства iBeacon, которое я регулярно использую в течение многих лет. По-прежнему нет игральных костей.

Когда я пытаюсь использовать собственный сканер Android BLE, я использую это:

ScanSettings settings = (new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)).setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES).build();
    List<ScanFilter> filters = new ArrayList<>(); // Make a scan filter matching the beacons I care about
    filters.add(new ScanFilter.Builder()/*.setServiceUuid(ParcelUuid.fromString("E2C56DB5-DFFB-48D2-B060-D0F5A71096E0"))*/.build());
    bluetoothAdapter.getBluetoothLeScanner().startScan(filters, settings, getPendingIntent(context));

и:

private PendingIntent getPendingIntent(Context context) {
    return PendingIntent.getBroadcast(context, 0, new Intent(context, BTDiscoveryBroadcast.class), PendingIntent.FLAG_UPDATE_CURRENT);
}

Я пробовал передавать null в качестве фильтров, пробовал пустой список массивов и пробовал реальный фильтр с тем же UUID.

По-прежнему ничего не работает.

то, что я случайно увидел в logcat, - это сообщение об ошибке:

E/NearbyDirect: Could not start scan. [CONTEXT service_id=49 ]
java.lang.IllegalStateException: Receiver com.google.location.nearby.direct.bluetooth.state.FastPairScanner$4@535d6ea registered with differing handler (was Handler (adxv) {8fab16a} now Handler (android.app.ActivityThread$H) {e4e0078})

Я думаю, что это происходит и при использовании библиотеки AltBeacon. Могу только предположить, что это связано с моей проблемой.

ИЗМЕНИТЬ 2: Я пробовал это:

ScanSettings settings = (new ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)).setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES).build();
            List<ScanFilter> filters = new ArrayList<>(); // Make a scan filter matching the beacons I care about
            byte[] manufacturerData = new byte[] {
                    // iBeacon identifier prefix
                    0x02, 0x15,
                    // Your Proximity UUID
                    (byte) 0xE2, (byte) 0xC5, 0x6D, (byte) 0xB5, (byte) 0xDF, (byte) 0xFB, 0x48, (byte) 0xD2, (byte) 0xB0, 0x60, (byte) 0xD0, (byte) 0xF5, (byte) 0xA7, 0x10, (byte) 0x96, (byte) 0xE0,
                        0x3, 0x20, 0x3, 0x20, (byte) 0xC5
            };
            int manufacturerId = 0x004c; // Apple
            filters.add(new ScanFilter.Builder().setManufacturerData(manufacturerId, manufacturerData).build());
            bluetoothAdapter.getBluetoothLeScanner().startScan(filters, settings, getPendingIntent(context));

Данные в байтах, которые я получил после выполнения обычного сканирования .startDiscovery, обнаружения моего устройства bt и извлечения данных из ScanResult. Просто чтобы убедиться, что он такой же.

По-прежнему не запускает трансляцию :(


person Alon Minski    schedule 08.03.2020    source источник
comment
Проблема может быть в вашем ScanFilter. Пожалуйста, покажите свой код. Я написал реализацию в Android Beacon Library, которая всегда использует фильтры сканирования с этим сканированием с намерением. Я могу подтвердить, что он работает и работает так же надежно, как и iOS, если вы правильно настроите фильтры сканирования.   -  person davidgyoung    schedule 08.03.2020
comment
@davidgyoung Привет, Дэвид, прежде всего позвольте мне поблагодарить вас за вашу замечательную библиотеку AltBeacon. Мы используем его годами, и это потрясающе! Делает свою работу и делает это хорошо. Я отредактировал свой OP с помощью кода. Спасибо за помощь.   -  person Alon Minski    schedule 09.03.2020
comment
Я думаю, вам нужно сделать шаг назад, прежде чем вы сможете решить эту проблему. Что РАБОТАЕТ? Сможете ли вы когда-нибудь обнаружить свой маяк в любых обстоятельствах с помощью вашего кода? Вы уверены, что знаете идентификатор своего радиобуя? Есть ли что-то еще принципиальное неправильное, например, отсутствие разрешений на Bluetooth или определение местоположения?   -  person davidgyoung    schedule 10.03.2020
comment
Разрешения предоставлены. Bluetooth включен. Есть 2 эффективных подхода. Во-первых, когда я просто вызываю bluetoothAdapter.startDiscovery (). При этом срабатывает широковещательный приемник, и я вижу все просканированные устройства. Но это не фоновое сканирование. Я могу просто вызывать это с интервалами и время от времени сканировать. Это не то, что я ищу. Второй подход, который работает, - это обеспечение вызова getBluetoothLeScanner (). StartScan с обратным вызовом вместо ожидающего намерения. Проблема здесь в добавлении фильтра. Обратный вызов прекращается. Хотя идентификатор правильный.   -  person Alon Minski    schedule 10.03.2020
comment
Здесь что-то не так. Вызов startDiscovery - это классическая операция Bluetooth. Это не должно напрямую влиять на сканирование BLE. Тот факт, что он внезапно приводит к появлению результатов сканирования BLE, предполагает, что это что-то разблокирует как побочный эффект. Возможно, ваш код каким-то образом блокирует потоки, которые Android использует для отправки обратных вызовов с намерением BLE, и выполнение startDiscovery каким-то образом сбрасывает Bluetooth, чтобы разблокировать эти потоки.   -  person davidgyoung    schedule 11.03.2020
comment
Я не уверен, связано ли это, но, возможно, исключение illigalstate, которое я видел (указанное в OP), могло быть каким-то образом связано?   -  person Alon Minski    schedule 11.03.2020


Ответы (1)


Если вы хотите настроить фильтр сканирования для поиска UUID маяка, подобный код не будет работать:

filters.add(new ScanFilter.Builder().setServiceUuid(ParcelUuid.fromString("E2C56DB5-DFFB-48D2-B060-D0F5A71096E0")).build());

Приведенный выше код установит фильтр для поиска устройства BLE, объявляющего UUID службы GATT, соответствующий E2C56DB5-DFFB-48D2-B060-D0F5A71096E0. UUID службы GATT не имеет абсолютно ничего общего с UUID близости маяка Bluetooth, хотя оба UUID могут внешне выглядеть одинаково. Другими словами, вы указываете фильтру искать подключаемое устройство Bluetooth, которое рекламирует настраиваемую услугу, которая просто совпадает с идентификатором вашего маяка. При этом ничего не найдешь, потому что такого устройства почти гарантированно не существует.

Вместо этого вы хотите сделать более сложным - вы хотите настроить фильтр сканирования, который будет искать рекламу производителя Bluetooth LE (например, рекламу iBeacon и AltBeacon), которая имеет конкретный код производителя и начинается с определенной последовательности байтов. .

Получить точную последовательность байтов для фильтра сложно, потому что это зависит как от идентификатора производителя, так и от макета маяка (iBeacon или AltBeacon). Это одна из многих сложностей, которые решает за вас Android Beacon Library.

Если вам действительно нужно сделать это самостоятельно, вы бы сделали что-то вроде этого для iBeacon (ВНИМАНИЕ: непроверенный код):

byte[] manufacturerData = new byte[] {
            // iBeacon identifier prefix
            0x02, 0x15, 
            // Your Proximity UUID
            0xE2, 0xC5, 0x6D, 0xB5, 0xDF, 0xFB, 0x48, 0xD2, 0xB0, 0x60, 0xD0, 0xF5, 0xA7, 0x10, 0x96, 0xE0
            };
int manufacturerId = 0x004c; // Apple
ScanFilter filter =
filters.add(new ScanFilter.Buider().setManufacturerData(manufacturerId, manufacturerData).build());
person davidgyoung    schedule 09.03.2020
comment
Я попробую это прямо сейчас. Но он по-прежнему не отвечает, почему, когда НЕ предоставляется какой-либо фильтр, трансляция не запускается при ЛЮБОМ типе обнаружения bt. Как я уже упоминал, я пробовал сканировать без какого-либо фильтра. Только сканировать настройки ожидающего намерения и все. И у меня рядом много маяков и bt-устройств. По-прежнему не запускается трансляция ... Я ожидал, что при отсутствии фильтра любая реклама bt вызовет трансляцию. Не так ли? - person Alon Minski; 10.03.2020
comment
Поддерживаемый намерением API разработан для работы с фильтром, в противном случае для операционной системы было бы слишком обременительно отправлять каждое обнаружение пакета Bluetooth через намерение. Я подозреваю, что это даже не сработает, если вы не предоставите фильтр, хотя вам придется проверить документы или исходный код Android, чтобы подтвердить. - person davidgyoung; 10.03.2020
comment
Я пробовал сканировать .startDiscovery. Нашел устройство bt, которое искал, извлек данные о его производителе (байты) и использовал их в качестве фильтра. (показано в последней редакции) ... Это все еще не сработало. Я тоже думаю, что что-то упускаю. Но на самом деле не вижу, что это такое. Код действительно прост. Должно работать! ржу не могу :) - person Alon Minski; 10.03.2020
comment
В конце мы решили сами инициировать сканирование с помощью RxBleClient, а затем проанализировать байтовые данные устройства с помощью вашего BeaconParser (от AltBeacon) и проверить его UUID. Сканирование выполняется с интервалами (удаленный параметр). - person Alon Minski; 11.03.2020