You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 02:35:21