提问人:UncannyHarmony 提问时间:10/27/2023 最后编辑:David WasserUncannyHarmony 更新时间:10/27/2023 访问量:40
android的蓝牙低功耗权限错误
Bluetooth low energy permission error for android
问:
我创建了一个应用程序来扫描和连接 BLE 设备,但不幸的是,每当启动 MainActivity(BLE 扫描)时,该应用程序都会不断崩溃,请帮助我找到代码中的错误,因为我已经实现了所有必要的 BLE 权限和运行时权限。
主要活动代码
public class BluetoothScanning extends AppCompatActivity {
private GifImageView imageView;
private boolean isScanning = false;
private BluetoothGatt bluetoothGatt;
private BluetoothGattCallback gattCallback;
private ActivityResultLauncher<Intent> enableBtLauncher;
private BluetoothAdapter bluetoothAdapter;
private ArrayList<String> deviceList;
private ArrayAdapter<String> adapter;
private Handler handler = new Handler();
private static final long SCAN_PERIOD = 60000; // 1 minute
private static final int REQUEST_ENABLE_BT = 1;
private static final int REQUEST_FINE_LOCATION = 2;
private ListView listView;
private Button scan;
private final BroadcastReceiver broadcastReceiver = 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);
String deviceName = device.getName();
String deviceAddress = device.getAddress();
String deviceInfo = deviceName + "\n" + deviceAddress;
if (!deviceList.contains(deviceInfo)) {
deviceList.add(deviceInfo);
adapter.notifyDataSetChanged();
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetoothscanning);
deviceList = new ArrayList<>();
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, deviceList);
imageView = findViewById(R.id.gif);
scan = findViewById(R.id.scanbutton);
listView = findViewById(R.id.devicelist);
listView.setAdapter(adapter);
scan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startBluetoothScan();
}
});
enableBtLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
startBluetoothScan();
} else {
Toast.makeText(this, "Bluetooth is required for this app to function", Toast.LENGTH_SHORT).show();
}
});
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
// Device doesn't support Bluetooth
Toast.makeText(this, "Bluetooth not supported", Toast.LENGTH_SHORT).show();
} else {
// Request Bluetooth and Location permissions at runtime
if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN,Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
} else {
// Permissions are already granted, start scanning
scan.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startBluetoothScan();
}
});
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
enableBtLauncher.launch(enableBtIntent);
} else {
// Bluetooth is already enabled, start scanning
startBluetoothScan();
}
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
String deviceInfo = adapter.getItem(i);
String[] parts = deviceInfo.split("\n");
String deviceAddress = parts[1]; // Assuming the device address is the second part of the split string
// Call the method to connect to the selected Bluetooth device
connectToBluetoothDevice(deviceAddress);
}
});
}
}
}
private void connectToBluetoothDevice(String deviceAddress) {
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceAddress);
gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
// Device connected. Discover services here if necessary.
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
// Device disconnected. Handle disconnection here.
}
}
// Other callback methods for BLE operations can be implemented here
};
// Connect to the BLE device
bluetoothGatt = device.connectGatt(this, false, gattCallback);
}
// Your existing methods
@Override
protected void onStart() {
super.onStart();
registerReceiver(bluetoothStateReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onStop() {
super.onStop();
unregisterReceiver(bluetoothStateReceiver);
stopScan();
}
private void startBluetoothScan() {
if (bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
}
bluetoothAdapter.startDiscovery();
// Register for broadcasts when a device is discovered
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(broadcastReceiver, filter);
handler.postDelayed(new Runnable() {
@Override
public void run() {
stopScan();
}
}, SCAN_PERIOD);
isScanning = true;
scan.setText("Stop Scan");
}
public void stopScan() {
scan.setText("Scan Again");
bluetoothAdapter.cancelDiscovery();
handler.removeCallbacksAndMessages(null); // Remove any pending callbacks
isScanning = false;
// Change the image in the ImageView here
imageView.setImageResource(R.drawable.bluetoothscanningfail);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (bluetoothAdapter != null) {
bluetoothAdapter.cancelDiscovery();
}
// Unregister the broadcast receiver
unregisterReceiver(bluetoothStateReceiver);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_FINE_LOCATION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, start scanning
startBluetoothScan();
} else {
// Permission denied, handle accordingly
Toast.makeText(this, "Location permission is required for Bluetooth scanning", Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ENABLE_BT) {
if (resultCode == RESULT_OK) {
// Bluetooth is enabled, start scanning
startBluetoothScan();
} else {
// User denied enabling Bluetooth, handle this scenario accordingly
Toast.makeText(this, "Bluetooth is required for this app to function", Toast.LENGTH_SHORT).show();
}
}
}
private final BroadcastReceiver bluetoothStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
BluetoothAdapter.ERROR);
switch (state) {
case BluetoothAdapter.STATE_OFF:
Toast.makeText(context, "Please TURN ON Bluetooth", Toast.LENGTH_SHORT).show();
// Bluetooth has been turned off;
break;
case BluetoothAdapter.STATE_TURNING_OFF:
// Bluetooth is turning off;
Toast.makeText(context, "Bluetooth is Turning OFF", Toast.LENGTH_SHORT).show();
break;
case BluetoothAdapter.STATE_ON:
// Bluetooth is on
Toast.makeText(context, "Bluetooth is ON", Toast.LENGTH_SHORT).show();
break;
case BluetoothAdapter.STATE_TURNING_ON:
// Bluetooth is turning on
Toast.makeText(context, "Bluetooth is Turning ON", Toast.LENGTH_SHORT).show();
break;
}
}
}
};
}
清单文件权限
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
LogCat 错误
FATAL EXCEPTION: main
Process: com.example.digilocktrial, PID: 26896
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.digilocktrial/com.example.digilocktrial.BluetoothScanning}: java.lang.SecurityException: Need android.permission.BLUETOOTH_SCAN permission for AttributionSource { uid = 10187, packageName = com.example.digilocktrial, attributionTag = null, token = android.os.BinderProxy@487b245, next = null }: AdapterService isDiscovering
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3782)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8177)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
Caused by: java.lang.SecurityException: Need android.permission.BLUETOOTH_SCAN permission for AttributionSource { uid = 10187, packageName = com.example.digilocktrial, attributionTag = null, token = android.os.BinderProxy@487b245, next = null }: AdapterService isDiscovering
at com.android.bluetooth.Utils.checkPermissionForDataDelivery(Utils.java:554)
at com.android.bluetooth.Utils.checkScanPermissionForDataDelivery(Utils.java:613)
at com.android.bluetooth.btservice.AdapterService$AdapterServiceBinder.isDiscovering(AdapterService.java:2342)
at com.android.bluetooth.btservice.AdapterService$AdapterServiceBinder.isDiscovering(AdapterService.java:2332)
at android.bluetooth.IBluetooth$Stub.onTransact(IBluetooth.java:1024)
at android.os.Binder.execTransactInternal(Binder.java:1344)
at android.os.Binder.execTransact(Binder.java:1275)
答: 暂无答案
评论
android-studio
ActivityCompat.requestPermissions(this, new String[]{});
BLUETOOTH_SCAN
BLUETOOTH_SCAN