Android蓝牙设备列表兼容问题:SDK33可用,SDK30无法显示
蓝牙设备列表兼容API24-33问题排查与修复
问题描述
我开发了一款安卓蓝牙设备列表应用,在API33设备上运行正常,但API30设备上无法显示设备列表,页面空白。需要修改代码以兼容API24至API33版本,请问问题出在权限还是广播接收器?以下是当前在高版本运行的代码和Manifest配置。
问题根源分析
主要问题出在权限处理逻辑混乱以及版本适配缺失,并非广播接收器本身的问题:
- 权限请求冲突:原代码中
checkPermissions()和checkLocationPermission()重复请求权限,且请求码与回调不匹配,导致权限授予后无法触发扫描; - API版本适配错误:API31之前(包括API30)不需要
BLUETOOTH_SCAN/BLUETOOTH_CONNECT权限,反而依赖位置权限,但原代码在低版本也请求高版本权限,导致逻辑混乱; - Manifest权限声明未做版本隔离:高版本权限未限制最低SDK版本,低版本系统无法识别这些权限,可能导致权限请求失败。
修复后的代码
MainActivity.java
package com.example.bttest; import android.Manifest; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; 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 android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private static final String TAG = "BluetoothActivity"; private static final int REQUEST_ENABLE_BT = 1; private static final int PERMISSION_REQUEST_LOCATION = 2; // 统一位置权限请求码 private static final int PERMISSION_REQUEST_BT_SCAN = 3; // 高版本蓝牙扫描权限请求码 private BluetoothAdapter bluetoothAdapter; private ArrayAdapter<String> deviceListAdapter; private List<String> deviceList; private BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device == null) return; String deviceName = device.getName() != null ? device.getName() : "未知设备"; String deviceAddress = device.getAddress(); String deviceInfo = deviceName + " - " + deviceAddress; if (!deviceList.contains(deviceInfo)) { // 避免重复添加设备 deviceList.add(deviceInfo); deviceListAdapter.notifyDataSetChanged(); } } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = findViewById(R.id.listView); deviceList = new ArrayList<>(); deviceListAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, deviceList); listView.setAdapter(deviceListAdapter); bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter == null) { Toast.makeText(this, "该设备不支持蓝牙", Toast.LENGTH_SHORT).show(); finish(); } } @Override protected void onStart() { super.onStart(); if (!bluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } else { checkRequiredPermissions(); } } @Override protected void onResume() { super.onResume(); IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(receiver, filter); } @Override protected void onPause() { super.onPause(); if (bluetoothAdapter != null && bluetoothAdapter.isDiscovering()) { bluetoothAdapter.cancelDiscovery(); } unregisterReceiver(receiver); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_ENABLE_BT) { if (resultCode == RESULT_OK) { checkRequiredPermissions(); } else { Toast.makeText(this, "蓝牙未启用", Toast.LENGTH_SHORT).show(); finish(); } } } private void checkRequiredPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // API31及以上 仅需BLUETOOTH_SCAN权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_SCAN}, PERMISSION_REQUEST_BT_SCAN); } else { startDiscovery(); } } else { // API30及以下 需要位置权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_LOCATION); } else { startDiscovery(); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSION_REQUEST_LOCATION || requestCode == PERMISSION_REQUEST_BT_SCAN) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { startDiscovery(); } else { Toast.makeText(this, "必要权限被拒绝,无法扫描蓝牙设备", Toast.LENGTH_SHORT).show(); finish(); } } } private void startDiscovery() { deviceList.clear(); deviceListAdapter.notifyDataSetChanged(); if (bluetoothAdapter.isDiscovering()) { bluetoothAdapter.cancelDiscovery(); } // API31+扫描前检查权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { return; } } bluetoothAdapter.startDiscovery(); Log.d(TAG, "开始扫描蓝牙设备"); Toast.makeText(this, "正在扫描蓝牙设备...", Toast.LENGTH_SHORT).show(); } }
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <!-- 基础蓝牙权限(API30及以下) --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" /> <!-- 位置权限(API30及以下扫描蓝牙必需) --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> <!-- 高版本蓝牙权限(API31及以上) --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:minSdkVersion="31" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" android:minSdkVersion="31" /> <!-- 声明设备支持蓝牙 --> <uses-feature android:name="android.hardware.bluetooth" android:required="true" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.BTTEst" tools:targetApi="33"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
修复要点总结
- 按API版本拆分权限逻辑:API31+使用
BLUETOOTH_SCAN权限,API30及以下使用位置权限; - 统一权限请求码与回调处理,确保权限授予后能触发扫描;
- Manifest中通过
android:minSdkVersion/android:maxSdkVersion隔离不同版本的权限声明,避免系统兼容性问题; - 广播接收器添加空值判断和重复设备过滤,提升稳定性;
- 在
onPause中主动取消扫描,减少后台耗电。
内容的提问来源于stack exchange,提问作者Portales Verticales
相关产品推荐
相关产品推荐

