Bluetooth
Android's Bluetooth APIs let an app discover nearby Bluetooth devices and exchange data with them — everything from headphones to fitness bands to, as we'll use for our example, a kitchen scale.
Imagine a future RecipeBox feature: instead of typing "200g flour" by hand while entering ingredients, the user places a bowl on a Bluetooth kitchen scale and RecipeBox reads the weight directly. It's not a core feature of the app today, but it's a realistic, motivating example for these APIs.
Permissions on Android 12+ (API 31+)
Older Android versions used a single blanket BLUETOOTH permission. Starting with Android 12 (API 31), Google split Bluetooth access into more granular, purpose-specific runtime permissions — the same runtime permission model covered in Runtime Permissions:
| Permission | Needed for |
|---|---|
| BLUETOOTH_SCAN | Discovering nearby devices (scanning) |
| BLUETOOTH_CONNECT | Connecting to and communicating with an already-known device |
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
Requesting them at runtime works exactly the same way as any other dangerous permission:
if (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);
}
Checking and Enabling Bluetooth
BluetoothManager btManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter adapter = btManager.getAdapter();
if (adapter == null) {
// Device has no Bluetooth radio at all
} else if (!adapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Discovering Nearby Devices
Scanning for devices is asynchronous: you start discovery, then listen for a broadcast per device found — the same BroadcastReceiver pattern from Broadcast Receivers:
private final BroadcastReceiver deviceFoundReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String name = device.getName();
String address = device.getAddress();
// Add to a "nearby devices" list, e.g. for picking the kitchen scale
}
}
};
// Register once, e.g. in onCreate()
registerReceiver(deviceFoundReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
// Start scanning (requires BLUETOOTH_SCAN permission granted)
adapter.startDiscovery();
Bluetooth Low Energy (BLE)
Everything above describes "classic" Bluetooth. Most modern smart kitchen devices — scales included — actually use Bluetooth Low Energy (BLE) instead, a more battery-efficient variant designed for small, infrequent bursts of data rather than continuous audio-style streaming. BLE communication revolves around GATT services and characteristics, which is a meaningfully different (and deeper) API surface than classic Bluetooth sockets.