Регистрация приемника вещания динамически не работает - 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 на Зефире выглядит следующим образом:
Есть
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" />
Убедитесь, что у вас есть разрешение во время выполнения для
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; } }
}
Зарегистрировать приемник вещания для
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), нужно было перезапустить, прежде чем трансляции продолжали получать.
Тем не менее, в моем случае я получал их без проблем, пока они (случайно?) Не перестали получать, и независимо от того, что я делал (закрыть приложение, переустановить приложение), трансляции не получали.