用于蓝牙设备发现的 BroadcastReceiver 适用于一台设备,但不适用于另一台设备

Wil*_*zel 2 android bluetooth bluetooth-device-discovery

代码:

我使用从此处获取的以下代码,目标 API 级别为 23(最低 API 级别为 18)。

private final BroadcastReceiver mReceiver = new BroadcastReceiver()
{
    public void onReceive(Context context, Intent intent)
    {
        String action = intent.getAction();

        if (BluetoothDevice.ACTION_FOUND.equals(action))
        {
            bluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            deviceNameTextView.setText(bluetoothDevice.getName());
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

在按下按钮的事件中我调用:

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
mBluetoothAdapter.startDiscovery(); // was initialized successsfully
Run Code Online (Sandbox Code Playgroud)

我的 AndroidManifest.xml 包含:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
Run Code Online (Sandbox Code Playgroud)

设备:

  1. 三星 Galaxy S III(API 级别 18)
  2. 索尼 Xperia Z3(API 级别 23)

事实:

  • 两个设备都运行完全相同的代码
  • 设备 1 可以发现设备 2(以及任何其他蓝牙设备)
  • 设备 2 无法发现设备 1(或任何其他蓝牙设备)
  • 两个设备均可发现
  • 使用标准系统对话框测试了可发现性,以成功配对两个设备
  • 两台设备始终未配对(我不想配对)
  • 不会引发任何异常。

怎么了?

更新 1: 由于 API 级别 23,可能必须在运行时请求权限。伊薇特给我指出了这一点,谢谢!不幸的是它没有解决我的问题。

与她的理论相悖的事实如下:

mBluetoothAdapter.startDiscovery()返回 true,表示成功(参见此处)。

// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity , Manifest.permission.BLUETOOTH_ADMIN);

if(permissionCheck == PackageManager.PERMISSION_GRANTED)
    Log.i("info", "Permission granted!");
else
    Log.i("info", "Permission not granted!");
Run Code Online (Sandbox Code Playgroud)

使用BLUETOOTH_ADMIN和运行此代码BLUETOOTH两次都会返回:

许可授予!

Wil*_*zel 5

在进行一些研究时,我从官方文档中发现了以下有关 Android 6.0(API 级别 23)更改的文章。

要通过蓝牙和 Wi-Fi 扫描访问附近外部设备的硬件标识符,您的应用程序现在必须具有 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 权限:
- WifiManager.getScanResults()
- BluetoothDevice.ACTION_FOUND
- BluetoothLeScanner.startScan()

ACCESS_FINE_LOCATION所以,我一直缺少权限ACCESS_COARSE_LOCATION。但仅仅将它们添加到AndroidManifest.xml文件中是不够的。您必须像 Yvette 建议的那样在运行时请求这些权限。

您可以在此处找到如何执行此操作,或者仅使用我编写的这段代码来获取蓝牙发现所需的权限。

final int CODE = 5; // app defined constant used for onRequestPermissionsResult

String[] permissionsToRequest =
{
    Manifest.permission.BLUETOOTH_ADMIN,
    Manifest.permission.BLUETOOTH,
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.ACCESS_COARSE_LOCATION
};

boolean allPermissionsGranted = true;

for(String permission : permissionsToRequest)
{
    allPermissionsGranted = allPermissionsGranted && (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED);
}

if(!allPermissionsGranted)
{
    ActivityCompat.requestPermissions(this, permissionsToRequest, CODE);
}

mBluetoothAdapter.startDiscovery();
Run Code Online (Sandbox Code Playgroud)

此代码假设用户授予权限(为了简单起见)。如果您希望应用程序在未授予权限时表现不同,请参阅本文中的“处理权限请求响应