我正在编写一个非常简单的测试 Android 应用程序,它可以发现蓝牙设备并将其显示在屏幕上。此应用程序在 Android 9 上正常运行,但在 Android 12 上无法正常运行。 我在请求权限时没有遇到任何问题,并且它可以正确检测到它们。事实上,它成功运行了 bluetoothAdapter.startDiscovery(),但 BroadcastReceiver 没有向我显示任何设备。 我一直无法找到原因,也不知道可能是什么问题。请任何人帮助我,或者有人知道在高于 Android 12 的版本中执行此功能的代码示例吗?
这是执行blueetoothAdapter.startDiscovery()方法后的Android Logcat
2023-06-22 13:33:16.317 10495-10495 蓝牙适配器 com.example.discoverydevicestest 我开始Discovery 2023-06-22 13:33:16.322 10495-10495 DiscoveryTest com.example.discoverydevicestest E 发现设备启动 2023-06-22 13:33:16.327 10495-10495 Toast com.example.discoverydevicestest V 显示:来电者 = com.example.discoverydevicestest.DiscoveryAndroid12.startDiscovery:199 2023-06-22 13:33:16.327 10495-10495 Toast com.example.discoverydevicestest V 显示:focusDisplayId = 0,isFocusInDesktop = false mCustomDisplayId=-1 isDexDualMode=false 2023-06-22 13:33:16.327 10495-10495 Toast com.example.discoverydevicestest V 显示:isActivityContext = true
我的代码
public class DiscoveryAndroid12 extends AppCompatActivity {
private static final String TAG = "DiscoveryTest";
private static final int REQUEST_ENABLE_BLUETOOTH = 1;
private static final int REQUEST_PERMISSION_LOCATION = 2;
private static final int REQUEST_BLUETOOTH_SCAN_PERMISSION = 3;
private static final int REQUEST_BLUETOOTH_CONNECT_PERMISSION = 4;
private static final int REQUEST_BLUETOOTH_A12_PERMISSIONS = 5;
private BluetoothAdapter bluetoothAdapter;
private ArrayAdapter<String> deviceListAdapter;
private List<BluetoothDevice> discoveredDevices;
private Button discoverButton;
private ListView deviceListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
discoverButton = findViewById(R.id.discoverButton);
deviceListView = findViewById(R.id.deviceListView);
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
discoveredDevices = new ArrayList<>();
deviceListAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
deviceListView.setAdapter(deviceListAdapter);
discoverButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
discoverDevices();
}
});
deviceListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
connectToDevice(position);
}
});
// Check if the device has bluetooth
if (bluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not supported on this device", Toast.LENGTH_SHORT).show();
finish();
}
// Register for broadcasts when a device is discovered.
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(receiver, filter);
}
// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
Log.e(TAG, "Device detected!");
// Discovery has found a device. Get the BluetoothDevice
// object and its info from the Intent.
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
}
String deviceName = device.getName();
String deviceHardwareAddress = device.getAddress(); // MAC address
Log.e(TAG, "Device found: " + deviceName + ": " + deviceHardwareAddress);
discoveredDevices.add(device);
String show = (deviceName != null) ? deviceName + ": " + deviceHardwareAddress : "Unknown name: " + deviceHardwareAddress;
deviceListAdapter.add(show);
}
}
};
private void discoverDevices() {
Log.e(TAG, "Starting process to search devices...");
boolean isGranted = true;
//Check permissions
if (Build.VERSION.SDK_INT >= 31) {
isGranted = checkBTScanAndConnectPermissions();
} else {
isGranted = checkLocationPermission();
}
if (isGranted) { //If permissions are granted
// Check if bluetooth is enabled
if (!bluetoothAdapter.isEnabled()) {
Log.e(TAG, "BT disabled, requesting user to enable it");
Intent enableBluetoothIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBluetoothIntent, REQUEST_ENABLE_BLUETOOTH);
} else {
Log.e(TAG, "BT enabled, starting dicovery");
startDiscovery();
}
}
}
private boolean checkLocationPermission() {
Log.e(TAG, "Checking LOCATION permissions...");
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSION_LOCATION);
return false;
} else {
Log.e(TAG, "Location permission granted");
return true;
}
}
private boolean checkScanPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN)
!= PackageManager.PERMISSION_GRANTED) {
Log.e(TAG, "BLUETOOTH_SCAN permission is not granted, requesting it...");
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_SCAN}, REQUEST_BLUETOOTH_SCAN_PERMISSION);
return false;
} else {
Log.e(TAG, "BLUETOOTH_SCAN permission granted");
return true;
}
}
@RequiresApi(api = Build.VERSION_CODES.S)
private boolean checkBTScanAndConnectPermissions() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT}, REQUEST_BLUETOOTH_A12_PERMISSIONS);
return false;
} else {
Log.e(TAG, "BLUETOOTH SCAN and CONNECT permissions granted");
return true;
}
}
private void startDiscovery() {
boolean isGranted = true;
deviceListAdapter.clear();
discoveredDevices.clear();
// Starting BT devices discovery
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= 31) {
isGranted = checkScanPermission();
}
}
if (isGranted) {
Log.e(TAG, "BT scan permissions already granted");
bluetoothAdapter.startDiscovery();
Log.e(TAG, "Discovery devices start");
Toast.makeText(this, "Discovering devices...", Toast.LENGTH_SHORT).show();
}
}
private void connectToDevice(int position) {
BluetoothDevice device = discoveredDevices.get(position);
// Actions to connect to BT device
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
}
Toast.makeText(this, "Connecting to device: " + device.getName(), Toast.LENGTH_SHORT).show();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_ENABLE_BLUETOOTH) {
if (resultCode == RESULT_OK) {
startDiscovery();
Toast.makeText(this, "Bluetooth enabled", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Bluetooth activation was canceled", Toast.LENGTH_SHORT).show();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_PERMISSION_LOCATION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
discoverDevices();
} else {
Toast.makeText(this, "Location permission denied", Toast.LENGTH_SHORT).show();
}
}
if (requestCode == REQUEST_BLUETOOTH_SCAN_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startDiscovery();
Toast.makeText(this, "Scan permission granted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Scan permission denied", Toast.LENGTH_SHORT).show();
}
}
if (requestCode == REQUEST_BLUETOOTH_A12_PERMISSIONS) {
boolean isgranted = true;
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Scan permission granted");
Toast.makeText(this, "Scan permission granted", Toast.LENGTH_SHORT).show();
} else {
Log.d(TAG, "Scan permission denied");
Toast.makeText(this, "Scan permission denied", Toast.LENGTH_SHORT).show();
isgranted = false;
}
if (grantResults.length > 0 && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Connect permission granted");
Toast.makeText(this, "Connect permission granted", Toast.LENGTH_SHORT).show();
} else {
Log.d(TAG, "Connect permission denied");
Toast.makeText(this, "Connect permission denied", Toast.LENGTH_SHORT).show();
isgranted = false;
}
if (isgranted){
discoverDevices();
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
}
bluetoothAdapter.cancelDiscovery();
}
}
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">
<!-- Request legacy Bluetooth permissions on older devices. -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>
<!-- Needed only if your app looks for Bluetooth devices.
You must add an attribute to this permission, or declare the
ACCESS_FINE_LOCATION permission, depending on the results when you
check location usage in your app. -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!-- Needed only if your app makes the device discoverable to Bluetooth
devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<!-- Needed only if your app communicates with already-paired Bluetooth
devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Needed only if your app uses Bluetooth scan results to derive physical location. -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<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:supportsRtl="true"
android:theme="@style/Theme.DiscoveryDevicesTest"
tools:targetApi="31">
<activity
android:name=".DiscoveryAndroid12"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.bluetooth.device.action.FOUND" />
</intent-filter>
</activity>
</application>
</manifest>
在 Android 12 中使用 BroadcastReceiver 时有什么需要注意的事项吗?
预先感谢您的贡献!
我正在开发 MAUI,并面临可用设备列表显示为空的问题。
这拯救了我的一天,非常感谢。