动态注册广播接收器不起作用--BluetoothDevice.ACTION_FOUND

时间:2015-09-18 16:07:48

标签: android android-broadcastreceiver

使用Log类跟踪运行时显示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

}

7 个答案:

答案 0 :(得分:36)

除了starting with Android 6.0 you have to have the ACCESS_COARSE_LOCATION permission to receive ACTION_FOUND(正如@siniux已经提到的那样)之外,还有另一个相关的事情:

ACCESS_COARSE_LOCATION属于dangerous permissions,您必须在运行时向用户明确请求(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)

因此,在Marshmallow 上发现BT设备的正确程序如下:

  1. 在清单中有ACCESS_COARSE_LOCATION权限要求以及通常的蓝牙权限:

    <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. {li>

    Ensure you have run-time permission 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();
    }
    
  4. 关于ACTION_NAME_CHANGED 的有趣之处。虽然6.0在未获得粗略位置许可的情况下无法向您发送ACTION_FOUND,但您仍会收到ACTION_NAME_CHANGED个事件,这些事件通常会在发现设备时与ACTION_FOUND合并。即你得到这两个事件,所以没有你的许可,你仍然可以处理ACTION_NAME_CHANGED几乎相同的行为。 (大师,如果我错了,请纠正我)

答案 1 :(得分:13)

我遇到了与广播接收器类似的问题。 然后我发现了这个: https://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id

基本上,在6.0上,您必须使用位置权限来扫描蓝牙设备。

答案 2 :(得分:7)

您错过的是您需要启动设备恢复

首先,获取蓝牙适配器

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

之后,您可以通过调用

来启动发现
mBtAdapter.startDiscovery();

您也应该在此处阅读详细信息,例如:关于cancelDiscovery() http://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#startDiscovery%28%29

P.S。此外,根据官方文档,建议使用context.getSystemService(Context.BLUETOOTH_SERVICE)在API 18+上获取BluetoothAdapter。

  

要获得代表本地蓝牙适配器的BluetoothAdapter,   在JELLY_BEAN_MR1及以下运行时,请调用静态   getDefaultAdapter()方法;在JELLY_BEAN_MR2及更高版本上运行时,   使用BLUETOOTH_SERVICE通过getSystemService(Class)检索它。

修改 请注意,startDiscovery()

需要BLUETOOTH_ADMIN权限

答案 3 :(得分:4)

我不知道你的代码是否正确获取蓝牙设备。这是我对你的代码的感觉。在函数内初始化和注册BroadcastReceiver是一个坏主意。你应该在onCreate()方法之外做。 这是您需要在代码中执行的操作

关于注册必须在此onCreate()中完成的Reciver

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()中的reciver不要忘记

并在discoverDevices()中只返回reciver为每次调用该函数而添加的list个设备;

答案 4 :(得分:1)

据专家回复,您可以查看以下几点以使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()方法。 当然,这对你有用...... 快乐的编码...

答案 5 :(得分:0)

将此作为答案发布,因为我无法评论我目前的代表级别。

您是否拥有包含在AndroidManifest.xml中的蓝牙权限?

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

如果没有,请分别尝试(和研究)每一个,因为我不记得每一个的重要性。

如果您有这些,请包含更多代码,以便诊断您的问题。

答案 6 :(得分:0)

我发现我在(Galaxy S4)上开发的设备需要重新启动,然后才能继续接收广播。

但是,就我而言,直到他们(随机?)停止接收并且无论我做什么(关闭应用程序,重新安装应用程序)都没有收到广播之前,我一直没有收到它们。