Android Studio蓝牙设备扫描问题求助:权限弹窗且无法获取设备名称
解决蓝牙扫描权限弹窗与设备名称获取问题
核心问题分析
- 权限适配不全:Android 12+ 需要单独申请
BLUETOOTH_SCAN、BLUETOOTH_CONNECT权限,旧版本则需位置权限,原代码未针对系统版本做适配,导致权限弹窗反复触发且扫描权限未正确获取。 - 设备名称获取逻辑缺陷:仅依赖扫描广播数据拿名称,忽略了部分设备广播无名称、需直接从
BluetoothDevice对象提取的情况。 - 扫描启动流程不严谨:未先确认蓝牙是否开启、权限是否授予就启动扫描,直接导致扫描失败。
修正后的完整代码
package com.example.bluetoothattendenceapplication; import android.Manifest; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanResult; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.widget.ArrayAdapter; import android.widget.ListView; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { private static final int REQUEST_BLUETOOTH_PERMISSIONS = 1001; private static final int REQUEST_ENABLE_BLUETOOTH = 1002; private BluetoothAdapter bluetoothAdapter; private BluetoothLeScanner bleScanner; private ListView deviceListView; private ArrayList<String> deviceList; private ArrayAdapter<String> adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); deviceListView = findViewById(R.id.device_list); deviceList = new ArrayList<>(); adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, deviceList); deviceListView.setAdapter(adapter); // 初始化蓝牙适配器 bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter == null) { Log.e("Bluetooth", "设备不支持蓝牙"); return; } // 检查蓝牙是否开启 if (!bluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BLUETOOTH); } else { checkPermissionsAndStartScan(); } } private void checkPermissionsAndStartScan() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12+ 专属权限 String[] permissions = { Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT }; if (checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED || checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { requestPermissions(permissions, REQUEST_BLUETOOTH_PERMISSIONS); return; } } else { // Android 11及以下所需权限 String[] permissions = { Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.BLUETOOTH }; if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(permissions, REQUEST_BLUETOOTH_PERMISSIONS); return; } } // 权限校验通过,启动扫描 startBleScan(); } private void startBleScan() { bleScanner = bluetoothAdapter.getBluetoothLeScanner(); if (bleScanner == null) { Log.e("Bluetooth", "BLE扫描功能不可用"); return; } bleScanner.startScan(scanCallback); Log.d("Bluetooth", "BLE扫描已启动"); } private final ScanCallback scanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); BluetoothDevice device = result.getDevice(); String deviceName = device.getName(); String deviceAddress = device.getAddress(); // 处理设备名称为空的情况 String displayName = (deviceName != null && !deviceName.isEmpty()) ? deviceName : "未知设备"; String deviceInfo = displayName + " (" + deviceAddress + ")"; // 避免重复添加同一设备 if (!deviceList.contains(deviceInfo)) { runOnUiThread(() -> { deviceList.add(deviceInfo); adapter.notifyDataSetChanged(); }); } } }; @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_ENABLE_BLUETOOTH) { if (resultCode == RESULT_OK) { checkPermissionsAndStartScan(); } else { Log.e("Bluetooth", "用户未开启蓝牙"); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_BLUETOOTH_PERMISSIONS) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } if (allGranted) { startBleScan(); } else { Log.e("Bluetooth", "权限未完全授予,无法扫描蓝牙设备"); } } } @Override protected void onDestroy() { super.onDestroy(); // 页面销毁时停止扫描,释放资源 if (bleScanner != null) { bleScanner.stopScan(scanCallback); } } }
关键优化说明
- 分版本权限适配:针对Android 12+和旧版本分别申请对应权限,减少不必要的弹窗,确保权限正确授予。
- 设备名称容错处理:直接从
BluetoothDevice对象提取名称,为空时显示“未知设备”,解决无名称设备无法识别的问题。 - 严谨的扫描流程:先确认蓝牙开启状态,再校验权限,最后启动扫描;页面销毁时主动停止扫描,避免资源浪费。
- 设备去重:添加设备前检查是否已存在,避免列表重复显示同一设备。
额外配置要求
在AndroidManifest.xml中添加权限声明:
<!-- 蓝牙基础权限(仅适配Android 11及以下) --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- Android 12+ 专属蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- Android 11及以下位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> <!-- 声明设备支持BLE蓝牙 --> <uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
内容的提问来源于stack exchange,提问作者Saachin Minde
相关产品推荐
相关产品推荐

