Регистрация приемника вещания динамически не работает - BluetoothDevice.ACTION_FOUND

С помощью Log класс для отслеживания Runtime показать, что onReceive() метод не называется, почему?

Динамически зарегистрировать приемник вещания

 private void discoverDevices () {
    Log.e("MOHAB","BEFORE ON RECEIVE");

     mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            Log.e("MOHAB","ON RECEIVE");
            String action = intent.getAction();
            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // Add the name and address to an array adapter to show in a ListView
                Bluetooth b = new Bluetooth(device.getName(),device.getAddress());
                list.add(b);
            }
        }
    };
    Log.e("MOHAB","create intentFilter");
    // Register the BroadcastReceiver
    IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
    registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy

}

6 ответов

Решение

Что вы пропустили, так это то, что вам нужно запустить восстановление устройства

Во-первых, получить адаптер Bluetooth

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

После этого вы начинаете обнаружение, позвонив

mBtAdapter.startDiscovery();

Вы должны прочитать подробности здесь, например, о cancelDiscovery() http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html

PS Также предлагается использовать context.getSystemService(Context.BLUETOOTH_SERVICE) чтобы получить BluetoothAdapter на API 18+, в соответствии с официальным документом.

Чтобы получить адаптер Bluetooth, представляющий локальный адаптер Bluetooth, при работе на JELLY_BEAN_MR1 и ниже вызовите статический метод getDefaultAdapter(); при работе на JELLY_BEAN_MR2 и выше, получите его через getSystemService(Class) с BLUETOOTH_SERVICE.

Изменить: Напоминаем, что вам необходимо разрешение BLUETOOTH_ADMIN для startDiscovery()

Помимо того, что начиная с Android 6.0 вы должны иметь ACCESS_COARSE_LOCATION разрешение на получение ACTION_FOUND (как уже упоминалось @siniux), есть еще одна связанная вещь:

ACCESS_COARSE_LOCATION относится к числу опасных разрешений, которые вы должны явно запрашивать у пользователя во время выполнения (еще одно улучшение безопасности, появившееся в 6.0).

Для диагностики вы можете запустить adb logcat | grep BroadcastQueue и увидеть что-то вроде этого:

W/BroadcastQueue: Permission Denial: receiving Intent { 
    act=android.bluetooth.device.action.FOUND flg=0x10 (has extras) } 
    to ProcessRecord{9007:com.examplepackage} (pid=9007, uid=10492) 
    requires android.permission.ACCESS_COARSE_LOCATION due to sender
    com.android.bluetooth (uid 1002)

Итак, правильная процедура обнаружения устройства BT на Зефире выглядит следующим образом:

  1. Есть ACCESS_COARSE_LOCATION требование разрешения в манифесте вместе с обычными разрешениями Bluetooth:

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    
  2. Убедитесь, что у вас есть разрешение во время выполнения для ACCESS_COARSE_LOCATION

    protected void checkLocationPermission() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
                != PackageManager.PERMISSION_GRANTED) {
    
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                    REQUEST_COARSE_LOCATION);
        }
    }
    
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
        switch (requestCode) {
        case REQUEST_COARSE_LOCATION: {
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                proceedDiscovery(); // --->
            } else {
                //TODO re-request
            }
            break;
        }
    }
    

    }

  3. Зарегистрировать приемник вещания для ACTION_FOUND и позвонить BluetoothAdapter.startDiscovery()

    protected void proceedDiscovery() {
        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothDevice.ACTION_NAME_CHANGED);
        registerReceiver(mReceiver, filter);
    
        mBluetoothAdapter.startDiscovery();
    }
    

Смешная вещь о ACTION_NAME_CHANGED, Хотя 6.0 не доставит вам ACTION_FOUND без разрешения на грубое местоположение, вы все равно получите ACTION_NAME_CHANGED события, которые обычно объединяются с ACTION_FOUND когда устройства обнаружены. Т.е. вы получаете оба события, поэтому без разрешения вы все равно можете обрабатывать ACTION_NAME_CHANGED для почти такого же поведения. (Гуру, поправьте меня, если я ошибаюсь)

У меня была похожая проблема с широковещательным приемником. Затем я нашел это: https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html

По сути, на 6.0 вы должны использовать разрешение на местоположение для поиска устройств Bluetooth.

Как ответили эксперты, вы можете проверить следующие пункты, чтобы заставить ACTION_FOUND работать в Android 6 и выше: 1. В дополнение к настройке разрешений BLUETOOTH и BLUETOOTH_ADMIN, попробуйте

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Иногда эти двое могут не понадобиться, но у меня это сработало. Также вы должны динамически искать разрешения пользователя, используя коды

int MY_PERMISSIONS_REQUEST = 200;
int permissions=ContextCompat.checkSelfPermission (this,Manifest.permission.ACCESS_FINE_LOCATION);
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                MY_PERMISSIONS_REQUEST);

Теперь напишите свои коды для выполнения требуемой операции. Я добавил один метод startDiscovery() сразу после этого. Конечно, это будет работать для вас... Удачного кодирования...

Я не знаю, если ваш код правильный в получении устройства Bluetooth. вот что я чувствую по поводу вашего кода. инициализация и регистрация BroadcastReceiver внутри функции - плохая идея. ты должен сделать это снаружи onCreate() метод. вот что вам нужно сделать в вашем коде

как о регистрации Reciver, что должно быть сделано в onCreate() как это

registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));

с инициализацией или приемником

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("MOHAB","ON RECEIVE");
            String action = intent.getAction();
            // When discovery finds a device
            if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                // Get the BluetoothDevice object from the Intent
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                // Add the name and address to an array adapter to show in a ListView
                Bluetooth b = new Bluetooth(device.getName(),device.getAddress());
                list.add(b);
            }
        }
    };

отменить регистрацию в onPause() не забудь этого

и в вашем discoverDevices() просто верните list устройств, добавленных получателем для каждого вызова этой фумиссии;

Публикуя это как ответ, я не могу комментировать свой текущий уровень репутации.

Есть ли у вас разрешение Bluetooth, включенное в ваш AndroidManifest.xml?

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

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

Если они у вас есть, пожалуйста, добавьте больше своего кода, чтобы можно было диагностировать вашу проблему.

Я обнаружил, что устройство, на котором я разрабатывал (Galaxy S4), нужно было перезапустить, прежде чем трансляции продолжали получать.

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

Другие вопросы по тегам