BluetoothAdapter — de systeemklasse van Android die de lokale Bluetooth-adapter van het apparaat vertegenwoordigt. BluetoothAdapter is het toegangspunt voor alle Bluetooth-bewerkingen op Android: radio inschakelen (enable), apparaten scannen, zichtbaarheid beheren (setScanMode), informatie over de adapter ophalen (getName, getAddress, getState). De klasse is beschikbaar via BluetoothManager.getAdapter() (API 18+) of BluetoothAdapter.getDefaultAdapter(). Op apparaten zonder Bluetooth-module retourneert getDefaultAdapter() null. Volgens Android Developers, 2026 is BluetoothAdapter een verplicht onderdeel voor elke BLE-applicatie op Android, vanaf API 5.
Belangrijkste punten
BluetoothAdapter vertegenwoordigt de fysieke Bluetooth-adapter van het Android-apparaat. Elk apparaat heeft precies één adapter (uitzondering — Android Automotive met meerdere Bluetooth-chips, waarbij BluetoothManager.getAdapterList() wordt gebruikt). BluetoothAdapter kapselt de status van de radio in: STATE_OFF (0), STATE_TURNING_ON (1), STATE_ON (2), STATE_TURNING_OFF (3). De status wordt gevolgd via BroadcastReceiver op ACTION_STATE_CHANGED.
Het verkrijgen van een BluetoothAdapter-instantie is de eerste stap van elke BLE-applicatie op Android. De aanbevolen methode — via BluetoothManager.getAdapter() vanaf API 18+. Alternatief — de statische methode BluetoothAdapter.getDefaultAdapter(), die werkt vanaf API 5 maar minder flexibel is. Beide methoden retourneren null als het apparaat geen Bluetooth-module heeft (Wi-Fi-only tablets, emulator). Null-controle is verplicht: de applicatie moet correct worden afgesloten of BLE-functies uitschakelen.
// BluetoothAdapter verkrijgen (aanbevolen)
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context
class BluetoothHelper(context: Context) {
private val bluetoothAdapter: BluetoothAdapter?
init {
// Methode 1: via BluetoothManager (API 18+)
val manager = context.getSystemService(Context.BLUETOOTH_SERVICE)
as BluetoothManager?
bluetoothAdapter = manager?.adapter
// Methode 2: via statische methode (API 5+)
// val adapter = BluetoothAdapter.getDefaultAdapter()
// Null-controle
if (bluetoothAdapter == null) {
// Apparaat ondersteunt geen Bluetooth
}
}
// Controleer Bluetooth-status
fun isBluetoothEnabled(): Boolean {
return bluetoothAdapter?.isEnabled == true
}
// Adapterinformatie ophalen
fun getAdapterInfo(): Map<String, String> {
return mapOf(
"name" to (bluetoothAdapter?.name ?: "N/A"),
"address" to (bluetoothAdapter?.address ?: "N/A"),
"state" to (bluetoothAdapter?.state?.toString() ?: "N/A"),
"scanMode" to (bluetoothAdapter?.scanMode?.toString() ?: "N/A")
)
}
}
De klasse BluetoothHelper demonstreert het verkrijgen van BluetoothAdapter via BluetoothManager met daaropvolgende null-controle. isBluetoothEnabled controleert isEnabled — een verplichte voorwaarde voor BLE-bewerkingen. getAdapterInfo retourneert de apparaatnaam, het MAC-adres, de status en de zichtbaarheidsmodus. Belangrijk: op Android 10+ (API 29+) retourneert de systeemservice een fictief MAC-adres (02:00:00:00:00:00) als de applicatie niet over de machtigingen BLUETOOTH_ADMIN en ACCESS_FINE_LOCATION beschikt.
BluetoothAdapter biedt methoden voor het beheren van de Bluetooth-radio. enable() en disable() schakelen Bluetooth in en uit. Beide methoden vereisen de machtiging BLUETOOTH_ADMIN en worden asynchroon uitgevoerd: na het aanroepen van enable() start het systeem het proces van radio-inschakeling, de status wordt gevolgd via BroadcastReceiver met de actie BluetoothAdapter.ACTION_STATE_CHANGED. Vanaf Android 10+ vereisen enable() en disable() een extra systeemmachtiging — gewone applicaties kunnen Bluetooth niet programmatisch beheren zonder gebruikersdialoog.
getState() retourneert de huidige status van de adapter: STATE_OFF (10), STATE_TURNING_ON (11), STATE_ON (12), STATE_TURNING_OFF (13). getAddress() retourneert het MAC-adres van de Bluetooth-adapter. Op Android 6+ is ACCESS_FINE_LOCATION vereist (of ACCESS_COARSE_LOCATION voor API 31+) voor het opvragen van het MAC-adres. Op Android 10+ retourneert getAddress() het constante adres 02:00:00:00:00:00 — het echte adres is niet beschikbaar via de openbare API.
getScanMode() bepaalt de zichtbaarheidsmodus van de adapter: SCAN_MODE_NONE (onzichtbaar), SCAN_MODE_CONNECTABLE (zichtbaar voor verbonden apparaten), SCAN_MODE_CONNECTABLE_DISCOVERABLE (zichtbaar voor iedereen). De zichtbaarheidsmodus is om veiligheidsredenen in tijd beperkt (meestal 60–300 seconden). Het instellen van de modus via setScanMode() vereist BLUETOOTH_ADMIN en systeemmachtiging op Android 10+.
| Methode | Beschrijving | Vereiste machtiging |
|---|---|---|
| enable() | Bluetooth-radio inschakelen | BLUETOOTH_ADMIN |
| disable() | Bluetooth-radio uitschakelen | BLUETOOTH_ADMIN |
| getState() | Huidige status van de adapter | BLUETOOTH |
| getAddress() | MAC-adres van de adapter | BLUETOOTH + ACCESS_FINE_LOCATION (API 23+) |
| getScanMode() | Zichtbaarheidsmodus van het apparaat | BLUETOOTH |
| setScanMode() | Zichtbaarheidsmodus instellen | BLUETOOTH_ADMIN |
BluetoothAdapter ondersteunt twee soorten scannen. Klassiek Bluetooth-scannen (BR/EDR) wordt gestart via startDiscovery() — detecteert Bluetooth-apparaten van alle typen, inclusief telefoons en headsets. Resultaten worden geretourneerd via BroadcastReceiver met de actie BluetoothDevice.ACTION_FOUND. startDiscovery() werkt 12 seconden en kan worden geannuleerd door cancelDiscovery() aan te roepen. Deze methode is verouderd voor BLE — gebruik BluetoothLeScanner.
BLE-scannen via BluetoothAdapter wordt uitgevoerd met de verouderde methode startLeScan(LeScanCallback). Vanaf API 21 raadt Google het gebruik van BluetoothLeScanner aan, verkregen via BluetoothAdapter.getBluetoothLeScanner(). BluetoothLeScanner biedt een flexibelere API: scanconfiguratie via ScanSettings (modus, callback type, match mode), filteren via ScanFilter (op service-UUID, apparaatnaam, MAC-adres) en ondersteuning voor PendingIntent voor scannen op de achtergrond.
// Oude (verouderde) vs nieuwe BLE-scan-API
import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.*
class BLEScanner(private val bluetoothAdapter: BluetoothAdapter?) {
// VEROUDERD: startLeScan (API 18+, API 21)
@Suppress("DEPRECATION")
fun legacyScan() {
bluetoothAdapter?.startLeScan { device, rssi, scanRecord ->
print("Found (LE Scan): $device.name, RSSI: $rssi")
}
}
// NIEUW: BluetoothLeScanner (API 21+)
fun modernScan() {
val scanner = bluetoothAdapter?.bluetoothLeScanner
?: return
// Scan-instellingen
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.build()
// Filteren op service (Hartslag UUID)
val filters = listOf(
ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
.build()
)
// Scannen starten
scanner.startScan(filters, settings, object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
val device = result.device
val rssi = result.rssi
print("Found (BLE Scanner): ${device.name}, RSSI: $rssi, address: ${device.address}")
}
override fun onScanFailed(errorCode: Int) {
print("Scan error: $errorCode")
}
})
}
}
De klasse BLEScanner vergelijkt de verouderde startLeScan en de moderne BluetoothLeScanner. In legacyScan ontvangt de callback LeScanCallback BluetoothDevice, RSSI en ruwe scanRecord. In modernScan wordt ScanSettings gebruikt met de modus LOW_LATENCY (maximale detectiesnelheid) en ScanFilter voor filtering op UUID van de hartslagservice (Heart Rate Service 0x180D). ScanCallback biedt onScanResult met een ScanResult-object met uitgebreide informatie: naam, RSSI, advertentiegegevens, verbindingstype.
BluetoothManager — de systeemservice van Android, geïntroduceerd in API 18 (Android 4.3), voor het beheren van Bluetooth-bewerkingen. Vóór API 18 was de enige manier om BluetoothAdapter te verkrijgen de statische methode getDefaultAdapter(). BluetoothManager biedt: adapter — de BluetoothAdapter-instantie, getConnectedDevices() — lijst van verbonden apparaten, getDevicesMatchingConnectionStates() — filteren op status. BluetoothManager wordt ook gebruikt voor het verkrijgen van BluetoothLeScanner op oudere API's.
Voordelen van BluetoothManager ten opzichte van directe aanroep van BluetoothAdapter.getDefaultAdapter(): de applicatie is niet afhankelijk van een statische singleton, de manager houdt rekening met de context (Activity/Application), wat belangrijk is voor multi-account scenario's in Android Enterprise. Op Android Automotive met meerdere Bluetooth-chips retourneert BluetoothManager.getAdapterList() alle beschikbare adapters — BluetoothAdapter.getDefaultAdapter() retourneert alleen de eerste.
// BluetoothManager gebruiken voor BLE
class BLEConnection(context: Context) {
private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val adapter: BluetoothAdapter? = bluetoothManager.adapter
// Lijst van verbonden BLE-apparaten ophalen
fun getConnectedDevices(): List<BluetoothDevice> {
return bluetoothManager.getConnectedDevices(
BluetoothProfile.GATT
)
}
// Apparaten filteren op status
fun getDevicesByState(states: IntArray): List<BluetoothDevice> {
return bluetoothManager.getDevicesMatchingConnectionStates(
BluetoothProfile.GATT, states
)
}
// BLE-ondersteuning op apparaat controleren
fun isBLESupported(): Boolean {
return adapter != null && context.packageManager
.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
}
// Bluetooth inschakelen via systeemdialoog aanvragen
fun requestEnableBluetooth(activity: MainActivity) {
if (adapter?.isEnabled == false) {
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
activity.startActivityForResult(intent, REQUEST_ENABLE_BT)
}
}
companion object {
const val REQUEST_ENABLE_BT = 1001
}
}
De klasse BLEConnection gebruikt BluetoothManager voor toegang tot BluetoothAdapter en het verkrijgen van de lijst met verbonden GATT-apparaten. isBLESupported controleert de aanwezigheid van BLE-radio via PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) — een belangrijke controle voor apparaten met Bluetooth Classic zonder BLE. requestEnableBluetooth toont het systeemdialoogvenster voor het inschakelen van Bluetooth (ACTION_REQUEST_ENABLE), zonder de machtiging BLUETOOTH_ADMIN — dit is de enige legale manier om Bluetooth in te schakelen op Android 10+ zonder systeemapplicatie.
Machtigingen voor BluetoothAdapter zijn met elke Android-versie geëvolueerd. Op Android 6–11 (API 23–30) zijn BLUETOOTH, BLUETOOTH_ADMIN en ACCESS_FINE_LOCATION verplicht voor BLE-scannen. Op Android 12+ (API 31+) heeft Google de machtigingen gesplitst: ACCESS_FINE_LOCATION is vervangen door BLUETOOTH_SCAN (scannen), BLUETOOTH_CONNECT (verbinden), BLUETOOTH_ADVERTISE (adverteren). Voor het zoeken naar BLE-apparaten is BLUETOOTH_SCAN voldoende, locatie is niet vereist.
Tabel met machtigingen per Android-versie:
| Operatie | API 23–30 | API 31+ |
|---|---|---|
| BLE-scannen | ACCESS_FINE_LOCATION | BLUETOOTH_SCAN (zonder locatie) |
| Verbinden met BLE | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT |
| BLE-adverteren | ACCESS_FINE_LOCATION | BLUETOOTH_ADVERTISE |
| In-/uitschakelen | BLUETOOTH_ADMIN | BLUETOOTH_ADMIN (systeem) |
| MAC-adres verkrijgen | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT (fictief adres) |
Op Android 12+ zijn alle Bluetooth-machtigingen runtime-machtigingen — ze moeten tijdens runtime worden aangevraagd via ActivityResultContracts.RequestMultiplePermissions. BLUETOOTH_SCAN en BLUETOOTH_ADVERTISE behoren tot de groep NEARBY_DEVICES, BLUETOOTH_CONNECT — tot dezelfde groep. De machtigingen BLUETOOTH en BLUETOOTH_ADMIN blijven in het manifest voor compatibiliteit met API < 31, maar voor API 31+ worden ze genegeerd — Google vereist expliciete vermelding van de nieuwe machtigingen.
// Bluetooth-machtigingen aanvragen op Android 12+
import android.Manifest
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.ContextCompat
class PermissionHelper(context: Context) {
fun getRequiredPermissions(): Array<String> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Android 12+: BLE-scannen
arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_ADVERTISE
)
} else {
// Android 6-11: BLE-scannen
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
)
}
}
// Alle machtigingen controleren
fun hasPermissions(context: Context): Boolean {
return getRequiredPermissions().all { permission ->
ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED
}
}
}
De klasse PermissionHelper retourneert de juiste set machtigingen op basis van het API-niveau. Op Android 12+ worden BLUETOOTH_SCAN, BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE zonder locatie gebruikt. Op Android 6–11 is voor BLE-scannen nog steeds ACCESS_FINE_LOCATION vereist. De ontwikkelaar moet beide scenario's in overweging nemen bij het aanvragen van machtigingen via ActivityResultContracts of RxPermissions.
Volledig voorbeeld van een BLE-applicatie in Kotlin die BluetoothAdapter gebruikt voor scannen, verbinden en lezen van gegevens van een BLE-apparaat. Het voorbeeld omvat het controleren van machtigingen, het verkrijgen van de adapter, scannen via BluetoothLeScanner en verbinden via BluetoothDevice.connectGatt.
// Volledige BLE-manager in Kotlin
class BLEManager(private val context: Context) {
private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val adapter: BluetoothAdapter? = bluetoothManager.adapter
private var scanner: BluetoothLeScanner? = adapter?.bluetoothLeScanner
private var gatt: BluetoothGatt? = null
// 1. Service-discovery
fun canScan(): Boolean {
return adapter?.isEnabled == true
&& scanner != null
&& PermissionHelper(context).hasPermissions(context)
}
// 2. Scannen met filter
fun startScanning(callback: (BluetoothDevice, Int) -> Unit) {
if (!canScan()) return
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(0)
.build()
scanner?.startScan(null, settings, object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
callback(result.device, result.rssi)
}
})
}
// 3. Scannen stoppen
fun stopScanning() {
scanner?.stopScan(object : ScanCallback() {})
}
// 4. Verbinden met BLE-apparaat
fun connectToDevice(device: BluetoothDevice) {
if (adapter?.isEnabled != true) return
gatt = device.connectGatt(
context,
false,
object : BluetoothGattCallback() {
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
gatt.discoverServices()
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
// Services gevonden, kenmerken kunnen worden gelezen
}
},
BluetoothDevice.TRANSPORT_LE
)
}
// 5. Bronnen vrijgeven
fun disconnect() {
gatt?.disconnect()
gatt?.close()
gatt = null
}
}
De manager BLEManager combineert de volledige BLE-cyclus op Android: controle van adapter en machtigingen (canScan), scannen via BluetoothLeScanner met ScanSettings (startScanning), verbinden via BluetoothDevice.connectGatt met TRANSPORT_LE (connectToDevice), vrijgeven van bronnen (disconnect). Alle BLE-bewerkingen worden uitgevoerd op de UI-thread — Android roept BluetoothGattCallback-callbacks aan op de hoofdthread. Voor productieve BLE-taken wordt aanbevolen GATT-bewerkingen naar een achtergrond-HandlerThread te verplaatsen.
Veelgestelde vragen
BluetoothAdapter — de klasse die de lokale Bluetooth-adapter van het Android-apparaat vertegenwoordigt. Verkregen via BluetoothManager.getAdapter() (API 18+) of BluetoothAdapter.getDefaultAdapter(). Biedt methoden voor het in-/uitschakelen van Bluetooth, scannen van apparaten, beheren van zichtbaarheid en ophalen van informatie over de adapter. Retourneert null op apparaten zonder Bluetooth-module.
De oorzaak is de afwezigheid van Bluetooth-radio op het apparaat. Kenmerkend voor Wi-Fi-only tablets, Android-emulator en Android TV zonder Bluetooth. Controleer getDefaultAdapter() op null bij het starten van de applicatie en schakel BLE-functies uit als de adapter ontbreekt. Alternatief — controle via PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) voor nauwkeurigere bepaling.
BluetoothLeScanner (API 21+) — moderne API voor BLE-scannen met ondersteuning voor ScanFilter, ScanSettings en PendingIntent. startLeScan (API 18+) — verouderde methode van BluetoothAdapter die LeScanCallback accepteert met een beperkte gegevensset. BluetoothLeScanner wordt door Google aanbevolen voor alle nieuwe projecten, maakt filteren op UUID, configureren van energieverbruiksmodus en werken op de achtergrond via PendingIntent mogelijk.
Op Android 12+ (API 31) is voor BLE-scannen BLUETOOTH_SCAN vereist, voor verbinden — BLUETOOTH_CONNECT, voor adverteren — BLUETOOTH_ADVERTISE. De locatiemachtiging ACCESS_FINE_LOCATION is niet langer vereist voor BLE. Op Android 6–11 is ACCESS_FINE_LOCATION nodig. Alle machtigingen worden tijdens runtime aangevraagd via ActivityResultContracts.
Vanaf Android 10+ is programmatisch inschakelen van Bluetooth zonder systeemdialoog alleen beschikbaar voor systeemapplicaties met de machtiging BLUETOOTH_PRIVILEGED. Gewone applicaties moeten Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) en startActivityForResult gebruiken — de gebruiker bevestigt het inschakelen in het systeemdialoogvenster. BLUETOOTH_ADMIN in het manifest geeft geen recht op enable() op Android 10+.
Conclusie
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook