BluetoothAdapter é uma classe de sistema Android que representa o adaptador Bluetooth local de um dispositivo. BluetoothAdapter é o ponto de entrada para todas as operações Bluetooth no Android: ativar o rádio (enable), escanear dispositivos, gerenciar visibilidade (setScanMode) e obter informações do adaptador (getName, getAddress, getState). A classe está disponível via BluetoothManager.getAdapter() (API 18+) ou BluetoothAdapter.getDefaultAdapter(). Em dispositivos sem módulo Bluetooth, getDefaultAdapter() retorna null. De acordo com Android Developers, 2026, BluetoothAdapter é um componente obrigatório para qualquer aplicação BLE no Android, a partir da API 5.
Principais pontos
BluetoothAdapter representa o adaptador Bluetooth físico de um dispositivo Android. Cada dispositivo tem exatamente um adaptador (exceto Android Automotive com múltiplos chips Bluetooth, que usa BluetoothManager.getAdapterList()). BluetoothAdapter encapsula o estado do rádio: STATE_OFF (0), STATE_TURNING_ON (1), STATE_ON (2), STATE_TURNING_OFF (3). O estado é rastreado via BroadcastReceiver em ACTION_STATE_CHANGED.
Obter uma instância do BluetoothAdapter é o primeiro passo de qualquer aplicação BLE no Android. O método recomendado é via BluetoothManager.getAdapter() a partir da API 18+. A alternativa é o método estático BluetoothAdapter.getDefaultAdapter(), que funciona desde a API 5 mas é menos flexível. Ambos os métodos retornam null se o dispositivo não tiver módulo Bluetooth (tablets somente Wi-Fi, emulador). A verificação de null é obrigatória: a aplicação deve encerrar corretamente ou desativar as funcionalidades BLE.
// Obter BluetoothAdapter (recomendado)
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context
class BluetoothHelper(context: Context) {
private val bluetoothAdapter: BluetoothAdapter?
init {
// Método 1: via BluetoothManager (API 18+)
val manager = context.getSystemService(Context.BLUETOOTH_SERVICE)
as BluetoothManager?
bluetoothAdapter = manager?.adapter
// Método 2: via método estático (API 5+)
// val adapter = BluetoothAdapter.getDefaultAdapter()
// Verificação de null
if (bluetoothAdapter == null) {
// Dispositivo não suporta Bluetooth
}
}
// Verificar estado do Bluetooth
fun isBluetoothEnabled(): Boolean {
return bluetoothAdapter?.isEnabled == true
}
// Obter informações do adaptador
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")
)
}
}
A classe BluetoothHelper demonstra como obter BluetoothAdapter via BluetoothManager com uma verificação de null posterior. isBluetoothEnabled verifica isEnabled — uma condição obrigatória antes de qualquer operação BLE. getAdapterInfo retorna o nome do dispositivo, endereço MAC, estado e modo de visibilidade. Importante: no Android 10+ (API 29+), o serviço do sistema retorna um endereço MAC fictício (02:00:00:00:00:00) se a aplicação não tiver permissões BLUETOOTH_ADMIN e ACCESS_FINE_LOCATION.
BluetoothAdapter fornece métodos para controlar o rádio Bluetooth. enable() e disable() ligam e desligam o Bluetooth. Ambos os métodos requerem a permissão BLUETOOTH_ADMIN e são executados de forma assíncrona: após chamar enable(), o sistema inicia o processo de ativação do rádio, e o estado é rastreado via BroadcastReceiver com a ação BluetoothAdapter.ACTION_STATE_CHANGED. No Android 10+, enable() e disable() exigem privilégio adicional do sistema — aplicações comuns não podem controlar o Bluetooth programaticamente sem um diálogo do usuário.
getState() retorna o estado atual do adaptador: STATE_OFF (10), STATE_TURNING_ON (11), STATE_ON (12), STATE_TURNING_OFF (13). getAddress() retorna o endereço MAC do adaptador Bluetooth. No Android 6+, é necessário ACCESS_FINE_LOCATION (ou ACCESS_COARSE_LOCATION para API 31+) para solicitar o endereço MAC. No Android 10+, getAddress() retorna o endereço constante 02:00:00:00:00:00 — o endereço real não está disponível através da API pública.
getScanMode() determina o modo de visibilidade do adaptador: SCAN_MODE_NONE (invisível), SCAN_MODE_CONNECTABLE (visível para dispositivos conectados), SCAN_MODE_CONNECTABLE_DISCOVERABLE (visível para todos). O modo de visibilidade é limitado no tempo (geralmente 60–300 segundos) por segurança. Definir o modo via setScanMode() requer BLUETOOTH_ADMIN e permissão do sistema no Android 10+.
| Método | Descrição | Permissão necessária |
|---|---|---|
| enable() | Ligar rádio Bluetooth | BLUETOOTH_ADMIN |
| disable() | Desligar rádio Bluetooth | BLUETOOTH_ADMIN |
| getState() | Estado atual do adaptador | BLUETOOTH |
| getAddress() | Endereço MAC do adaptador | BLUETOOTH + ACCESS_FINE_LOCATION (API 23+) |
| getScanMode() | Modo de visibilidade do dispositivo | BLUETOOTH |
| setScanMode() | Definir modo de visibilidade | BLUETOOTH_ADMIN |
BluetoothAdapter suporta dois tipos de varredura. A varredura Bluetooth clássica (BR/EDR) é iniciada via startDiscovery() — descobre dispositivos Bluetooth de todos os tipos, incluindo telefones e fones de ouvido. Os resultados são retornados via BroadcastReceiver com a ação BluetoothDevice.ACTION_FOUND. startDiscovery() funciona por 12 segundos e pode ser cancelado chamando cancelDiscovery(). Este método está obsoleto para BLE — use BluetoothLeScanner.
A varredura BLE via BluetoothAdapter utiliza o método obsoleto startLeScan(LeScanCallback). A partir da API 21, o Google recomenda usar BluetoothLeScanner, obtido via BluetoothAdapter.getBluetoothLeScanner(). BluetoothLeScanner fornece uma API mais flexível: configuração de varredura via ScanSettings (modo, tipo de callback, modo de correspondência), filtragem via ScanFilter (por UUID de serviço, nome do dispositivo, endereço MAC) e suporte a PendingIntent para varredura em segundo plano.
// API de varredura BLE antiga (obsoleta) vs nova
import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.*
class BLEScanner(private val bluetoothAdapter: BluetoothAdapter?) {
// OBSOLETO: startLeScan (API 18+, API 21)
@Suppress("DEPRECATION")
fun legacyScan() {
bluetoothAdapter?.startLeScan { device, rssi, scanRecord ->
print("Found (LE Scan): $device.name, RSSI: $rssi")
}
}
// NOVO: BluetoothLeScanner (API 21+)
fun modernScan() {
val scanner = bluetoothAdapter?.bluetoothLeScanner
?: return
// Configurações de varredura
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
.build()
// Filtrar por serviço (UUID de frequência cardíaca)
val filters = listOf(
ScanFilter.Builder()
.setServiceUuid(ParcelUuid.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
.build()
)
// Iniciar varredura
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")
}
})
}
}
A classe BLEScanner compara o obsoleto startLeScan com o moderno BluetoothLeScanner. No legacyScan, o LeScanCallback recebe BluetoothDevice, RSSI e scanRecord bruto. No modernScan, são usados ScanSettings com modo LOW_LATENCY (máxima velocidade de descoberta) e ScanFilter para filtrar pelo UUID do serviço de frequência cardíaca (0x180D). ScanCallback fornece onScanResult com um objeto ScanResult contendo informações estendidas: nome, RSSI, dados de publicidade, tipo de conexão.
BluetoothManager é um serviço de sistema Android, introduzido na API 18 (Android 4.3), para gerenciar operações Bluetooth. Antes da API 18, a única forma de obter BluetoothAdapter era o método estático getDefaultAdapter(). BluetoothManager fornece: adapter — uma instância de BluetoothAdapter, getConnectedDevices() — uma lista de dispositivos conectados, getDevicesMatchingConnectionStates() — filtragem por estado. BluetoothManager também é usado para obter BluetoothLeScanner em APIs antigas.
Vantagens do BluetoothManager sobre chamar diretamente BluetoothAdapter.getDefaultAdapter(): a aplicação não depende de um singleton estático, o gerenciador respeita o contexto (Activity/Application), o que é importante para cenários de múltiplas contas no Android Enterprise. No Android Automotive com vários chips Bluetooth, BluetoothManager.getAdapterList() retorna todos os adaptadores disponíveis — BluetoothAdapter.getDefaultAdapter() retorna apenas o primeiro.
// Usar BluetoothManager para BLE
class BLEConnection(context: Context) {
private val bluetoothManager: BluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
private val adapter: BluetoothAdapter? = bluetoothManager.adapter
// Obter lista de dispositivos BLE conectados
fun getConnectedDevices(): List<BluetoothDevice> {
return bluetoothManager.getConnectedDevices(
BluetoothProfile.GATT
)
}
// Filtrar dispositivos por estado
fun getDevicesByState(states: IntArray): List<BluetoothDevice> {
return bluetoothManager.getDevicesMatchingConnectionStates(
BluetoothProfile.GATT, states
)
}
// Verificar suporte BLE no dispositivo
fun isBLESupported(): Boolean {
return adapter != null && context.packageManager
.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
}
// Solicitar ativação de Bluetooth via diálogo do sistema
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
}
}
A classe BLEConnection usa BluetoothManager para acessar BluetoothAdapter e obter a lista de dispositivos GATT conectados. isBLESupported verifica a presença de rádio BLE via PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) — uma verificação importante para dispositivos com Bluetooth Classic sem BLE. requestEnableBluetooth mostra o diálogo do sistema para ativar Bluetooth (ACTION_REQUEST_ENABLE), sem exigir permissão BLUETOOTH_ADMIN — esta é a única forma legal de ativar Bluetooth no Android 10+ sem uma aplicação de sistema.
As permissões para BluetoothAdapter evoluíram com cada versão do Android. No Android 6–11 (API 23–30), BLUETOOTH, BLUETOOTH_ADMIN e ACCESS_FINE_LOCATION são obrigatórias para varredura BLE. No Android 12+ (API 31+), o Google dividiu as permissões: ACCESS_FINE_LOCATION é substituída por BLUETOOTH_SCAN (varredura), BLUETOOTH_CONNECT (conexão), BLUETOOTH_ADVERTISE (publicidade). Para descoberta de dispositivos BLE, BLUETOOTH_SCAN é suficiente, localização não é necessária.
Tabela de permissões por versão do Android:
| Operação | API 23–30 | API 31+ |
|---|---|---|
| Varredura BLE | ACCESS_FINE_LOCATION | BLUETOOTH_SCAN (sem localização) |
| Conexão BLE | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT |
| Publicidade BLE | ACCESS_FINE_LOCATION | BLUETOOTH_ADVERTISE |
| Ativar/desativar | BLUETOOTH_ADMIN | BLUETOOTH_ADMIN (sistema) |
| Obter endereço MAC | ACCESS_FINE_LOCATION | BLUETOOTH_CONNECT (endereço fictício) |
No Android 12+, todas as permissões Bluetooth são permissões de tempo de execução — devem ser solicitadas em tempo de execução via ActivityResultContracts.RequestMultiplePermissions. BLUETOOTH_SCAN e BLUETOOTH_ADVERTISE pertencem ao grupo NEARBY_DEVICES, BLUETOOTH_CONNECT pertence ao mesmo grupo. As permissões BLUETOOTH e BLUETOOTH_ADMIN permanecem no manifesto para compatibilidade com API < 31, mas para API 31+ são ignoradas — o Google exige especificar explicitamente as novas permissões.
// Solicitar permissões Bluetooth no 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-
arrayOf(
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_ADVERTISE
)
} else {
// Android 6-11: BLE
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
)
}
}
// Verificar todas as permissões
fun hasPermissions(context: Context): Boolean {
return getRequiredPermissions().all { permission ->
ContextCompat.checkSelfPermission(context, permission)
== PackageManager.PERMISSION_GRANTED
}
}
}
A classe PermissionHelper retorna o conjunto correto de permissões dependendo do nível da API. No Android 12+, são usados BLUETOOTH_SCAN, BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE sem localização. No Android 6–11, ACCESS_FINE_LOCATION ainda é necessário para varredura BLE. O desenvolvedor deve considerar ambos os cenários ao solicitar permissões via ActivityResultContracts ou RxPermissions.
Exemplo completo de uma aplicação BLE em Kotlin usando BluetoothAdapter para escanear, conectar e ler dados de um dispositivo BLE. O exemplo cobre a verificação de permissões, obtenção do adaptador, varredura via BluetoothLeScanner e conexão via BluetoothDevice.connectGatt.
// Gerenciador BLE completo em 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. Descoberta de serviços
fun canScan(): Boolean {
return adapter?.isEnabled == true
&& scanner != null
&& PermissionHelper(context).hasPermissions(context)
}
// 2. com filtro
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. Parar varredura
fun stopScanning() {
scanner?.stopScan(object : ScanCallback() {})
}
// 4. Conectar ao dispositivo BLE
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) {
// Serviços encontrados, pode ler características
}
},
BluetoothDevice.TRANSPORT_LE
)
}
// 5. Liberar recursos
fun disconnect() {
gatt?.disconnect()
gatt?.close()
gatt = null
}
}
A classe BLEManager unifica o ciclo BLE completo no Android: verificação do adaptador e permissões (canScan), varredura via BluetoothLeScanner com ScanSettings (startScanning), conexão via BluetoothDevice.connectGatt com TRANSPORT_LE (connectToDevice) e liberação de recursos (disconnect). Todas as operações BLE são executadas na thread da interface do usuário — o Android chama os callbacks BluetoothGattCallback na thread principal. Para tarefas BLE intensivas, recomenda-se transferir operações GATT para uma HandlerThread em segundo plano.
Perguntas frequentes
BluetoothAdapter é uma classe que representa o adaptador Bluetooth local de um dispositivo Android. É obtida via BluetoothManager.getAdapter() (API 18+) ou BluetoothAdapter.getDefaultAdapter(). Fornece métodos para ativar/desativar Bluetooth, escanear dispositivos, gerenciar visibilidade e obter informações do adaptador. Retorna null em dispositivos sem módulo Bluetooth.
A razão é a ausência de rádio Bluetooth no dispositivo. Típico em tablets somente Wi-Fi, emulador Android e Android TV sem Bluetooth. Verifique getDefaultAdapter() como null na inicialização da aplicação e desative funcionalidades BLE se o adaptador estiver ausente. Uma alternativa é verificar via PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) para detecção mais precisa.
BluetoothLeScanner (API 21+) é a API moderna para varredura BLE com suporte a ScanFilter, ScanSettings e PendingIntent. startLeScan (API 18+) é um método obsoleto do BluetoothAdapter que aceita LeScanCallback com um conjunto de dados limitado. O Google recomenda BluetoothLeScanner para todos os novos projetos, permite filtrar por UUID, configurar o modo de consumo de energia e operar em segundo plano via PendingIntent.
No Android 12+ (API 31), a varredura BLE requer BLUETOOTH_SCAN, a conexão requer BLUETOOTH_CONNECT e a publicidade requer BLUETOOTH_ADVERTISE. A permissão de localização ACCESS_FINE_LOCATION não é mais necessária para BLE. No Android 6–11, ACCESS_FINE_LOCATION é necessário. Todas as permissões são solicitadas em tempo de execução via ActivityResultContracts.
No Android 10+, a ativação programática de Bluetooth sem diálogo do sistema está disponível apenas para aplicações de sistema com permissão BLUETOOTH_PRIVILEGED. Aplicações comuns devem usar Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) e startActivityForResult — o usuário confirma a ativação no diálogo do sistema. BLUETOOTH_ADMIN no manifesto não concede direitos enable() no Android 10+.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também