15

使用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

}
4

7 回答 7

43

除了从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)

因此,在 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. 确保您具有运行时权限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几乎相同的行为。(大师,如果我错了,请纠正我)

于 2016-05-27T11:26:07.357 回答
13

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

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

于 2015-10-05T14:53:27.537 回答
8

您错过的是您需要开始设备发现

一、拿到蓝牙适配器

BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

之后,您通过调用开始发现

mBtAdapter.startDiscovery();

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

PScontext.getSystemService(Context.BLUETOOTH_SERVICE)另外,根据官方文档,建议使用在 API 18+ 上获取蓝牙适配器。

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

编辑: 请注意,您需要BLUETOOTH_ADMIN权限才能startDiscovery()

于 2015-09-18T16:40:26.790 回答
6

专家回复,为了让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() 方法。当然,这对你有用......快乐的编码......

于 2018-03-29T16:25:52.387 回答
4

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

至于注册必须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器为该功能的每次调用添加的设备;

于 2015-09-18T16:59:16.307 回答
0

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

您的 AndroidManifest.xml 中是否包含蓝牙许可?

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

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

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

于 2015-09-18T16:42:45.123 回答
0

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

但是,在我的情况下,我一直没有问题地接收它们,直到它们(随机?)停止接收并且无论我做什么(关闭应用程序,重新安装应用程序)都没有接收到广播。

于 2019-02-12T21:22:47.290 回答