安卓 - 蓝牙发现找不到任何设备



我目前正在开发一个小应用程序,以开始使用蓝牙Android API可以提供的服务。

编辑 -> 答案:

似乎问题是由于特定的Nexus 5设备引起的。似乎他们的蓝牙接收器不能正常工作。下面的解决方案应该适用于其他设备

备注:

  1. 我已经阅读了这里的文档:http://developer.android.com/guide/topics/connectivity/bluetooth.html以及本教程的以下源代码 http://www.londatiga.net/it/programming/android/how-to-programmatically-scan-or-discover-android-bluetooth-device/位于 github 上的/lorensiuswlt/AndroBluetooth 下

  2. 我已经完成了几乎所有我感兴趣的功能(例如检查适配器是否存在,启用/禁用blueooth,查询配对的divices,设置适配器可发现)。

问题:

实际上,当我启动.onDiscovery()方法时,即使从Nexus 5上的设置/蓝牙中找到设备,也没有找到任何设备

以下是我的处理方式:

public class MainActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
...
protected void onCreate(Bundle savedInstanceState) {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mReceiver, filter); 
}

据我所知,过滤器运行良好,即ACTION_STATE_CHANGED(在蓝牙启用上)和两个ACTION_DISCOVERY_***。

然后成功调用以下方法:

public void onDiscovery(View view)
{
    mBluetoothAdapter.startDiscovery();
}

然后我有我的蓝牙接收器:

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
            final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
            if (state == BluetoothAdapter.STATE_ON) {
                showToast("ACTION_STATE_CHANGED: STATE_ON");
            }
        }
        else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
            mDeviceList = new ArrayList<>();
            showToast("ACTION_DISCOVERY_STARTED");
            mProgressDlg.show();
        }
        else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action) && !bluetoothSwitchedOFF) {
            mProgressDlg.dismiss();
            showToast("ACTION_DISCOVERY_FINISHED");
            Intent newIntent = new Intent(MainActivity.this, DeviceListActivity.class);
            newIntent.putParcelableArrayListExtra("device.list", mDeviceList);
            startActivity(newIntent);
        }
        else if (BluetoothDevice.ACTION_FOUND.equals(action)) {// When discovery finds a device
            // Get the BluetoothDevice object from the Intent
            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            mDeviceList.add(device);
            showToast("Device found = " + device.getName());
        }
    }
};

我在 logcat 出来时没有任何问题,并且在我所做的测试中没有注意到任何麻烦。唯一的问题是,在扫描结束时没有发现任何设备,而周围有许多可发现的设备可用。

我尽量不放太多代码,以免淹没这个话题。问我是否需要更多。

感谢您阅读我,并提前感谢您的回答。

你在哪个版本的安卓上运行这个? 如果是Android 6.x,我认为您需要将ACCESS_FINE_LOCATION权限添加到清单中。例如:

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

有一个类似的问题,这为我解决了它。

更新:直接从谷歌添加有关此的文档:

若要通过蓝牙和 Wi-Fi 扫描访问附近外部设备的硬件标识符,你的应用现在必须具有ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION权限

2020 年更新:我们最近将应用程序更新为面向 SDK 版本 29。在此过程中,我们的应用程序不再能够再次发现蓝牙设备。自从这个答案最初写出来以来,我们一直在使用ACCESS_COARSE_LOCATION。更改为ACCESS_FINE_LOCATION似乎可以解决问题。我现在建议开发人员尝试ACCESS_FINE_LOCATION是否以 29+ 为目标。已更新答案以反映这一点。

派对有点晚了,但这可能会对其他人派上用场。

你需要做两件事

  1. 添加<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

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

到您的安卓清单.xml

  1. 确保您也使用类似这样的内容请求 Android 6.0 设备的运行时权限

    int MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 1; 
    ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
            MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);
    

    就在mBluetoothAdapter.startDiscovery();之前

如果不执行步骤 2,您将无法在装有 Android>= 6.0 的设备上获取任何硬件标识符信息

更新/编辑:
Android版本检查和警报对话框作为警告的示例

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {  // Only ask for these permissions on runtime when running Android 6.0 or higher
    switch (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.ACCESS_COARSE_LOCATION)) {
        case PackageManager.PERMISSION_DENIED:
            ((TextView) new AlertDialog.Builder(this)
                    .setTitle("Runtime Permissions up ahead")
                    .setMessage(Html.fromHtml("<p>To find nearby bluetooth devices please click "Allow" on the runtime permissions popup.</p>" +
                            "<p>For more info see <a href="http://developer.android.com/about/versions/marshmallow/android-6.0-changes.html#behavior-hardware-id">here</a>.</p>"))
                    .setNeutralButton("Okay", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            if (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                                ActivityCompat.requestPermissions(DeviceListActivity.this,
                                        new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                                        REQUEST_ACCESS_COARSE_LOCATION);
                            }
                        }
                    })
                    .show()
                    .findViewById(android.R.id.message))
                    .setMovementMethod(LinkMovementMethod.getInstance());       // Make the link clickable. Needs to be called after show(), in order to generate hyperlinks
            break;
        case PackageManager.PERMISSION_GRANTED:
            break;
    }
}

与新的安卓版本一样,情况发生了一些变化像android 10这样的较旧的Android版本需要FINE_LOCATION而像android 12这样的较新的Android版本也可以与COARSE_LOCATION一起使用。因此,我的建议是征求FINE_LOCATION许可,这将在两者中都有效。不要同时询问COAR_LOCATION和FINE_LOCATION,否则如果用户在应用程序启动时选择粗略位置,它将无法与 Android 12 及更高版本一起使用。

最新更新