BluetoothAdapter — co to jest, metody i zarządzanie Bluetooth w Androidzie

Autor: IT Sectr Opublikowano: 2026-07-16 Czas czytania: 10 min

BluetoothAdapter — systemowa klasa Androida reprezentująca lokalny adapter Bluetooth urządzenia. BluetoothAdapter to punkt wejścia dla wszystkich operacji Bluetooth na Androidzie: włączanie radia (enable), skanowanie urządzeń, zarządzanie widzialnością (setScanMode), pobieranie informacji o adapterze (getName, getAddress, getState). Klasa jest dostępna przez BluetoothManager.getAdapter() (API 18+) lub BluetoothAdapter.getDefaultAdapter(). Na urządzeniach bez modułu Bluetooth getDefaultAdapter() zwraca null. Według Android Developers, 2026, BluetoothAdapter to obowiązkowy komponent każdej aplikacji BLE na Androida, począwszy od API 5.

Najważniejsze

  • BluetoothAdapter — systemowa klasa Androida do zarządzania lokalnym adapterem Bluetooth urządzenia
  • getDefaultAdapter() — statyczna metoda do pobierania instancji; zwraca null na urządzeniach bez Bluetooth
  • getBluetoothLeScanner() — metoda dostępu do nowoczesnego skanera BLE (API 21+)
  • enable/disable — metody włączania i wyłączania radia Bluetooth (wymagają uprawnienia BLUETOOTH_ADMIN)
  • startDiscovery/startLeScan — metody klasycznego i BLE skanowania (LE Scan jest przestarzały, używaj BluetoothLeScanner)

Czym jest BluetoothAdapter: istota i pobieranie instancji

BluetoothAdapter reprezentuje fizyczny adapter Bluetooth urządzenia z Androidem. Każde urządzenie ma dokładnie jeden adapter (wyjątkiem jest Android Automotive z wieloma układami Bluetooth, gdzie używany jest BluetoothManager.getAdapterList()). BluetoothAdapter enkapsuluje stan radia: STATE_OFF (0), STATE_TURNING_ON (1), STATE_ON (2), STATE_TURNING_OFF (3). Stan jest śledzony przez BroadcastReceiver na ACTION_STATE_CHANGED.

Pobranie instancji BluetoothAdapter to pierwszy krok każdej aplikacji BLE na Androida. Zalecana metoda — przez BluetoothManager.getAdapter() od API 18+. Alternatywa — statyczna metoda BluetoothAdapter.getDefaultAdapter(), która działa od API 5, ale jest mniej elastyczna. Obie metody zwracają null, jeśli urządzenie nie ma modułu Bluetooth (tablety Wi-Fi-only, emulator). Sprawdzenie null jest obowiązkowe: aplikacja musi poprawnie zakończyć działanie lub wyłączyć funkcje BLE.

kotlin
// Pobieranie BluetoothAdapter (zalecane)
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context

class BluetoothHelper(context: Context) {

    private val bluetoothAdapter: BluetoothAdapter?

    init {
        // Metoda 1: przez BluetoothManager (API 18+)
        val manager = context.getSystemService(Context.BLUETOOTH_SERVICE)
                as BluetoothManager?
        bluetoothAdapter = manager?.adapter

        // Metoda 2: przez metodę statyczną (API 5+)
        // val adapter = BluetoothAdapter.getDefaultAdapter()

        // Sprawdzenie null
        if (bluetoothAdapter == null) {
            // Urządzenie nie obsługuje Bluetooth
        }
    }

    // Sprawdź stan Bluetooth
    fun isBluetoothEnabled(): Boolean {
        return bluetoothAdapter?.isEnabled == true
    }

    // Pobierz informacje o adapterze
    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")
        )
    }
}

Klasa BluetoothHelper demonstruje pobieranie BluetoothAdapter przez BluetoothManager z następną kontrolą null. isBluetoothEnabled sprawdza isEnabled — obowiązkowy warunek przed jakimikolwiek operacjami BLE. getAdapterInfo zwraca nazwę urządzenia, adres MAC, stan i tryb widzialności. Ważne: na Android 10+ (API 29+) system service zwraca fikcyjny adres MAC (02:00:00:00:00:00), jeśli aplikacja nie ma uprawnienia BLUETOOTH_ADMIN i ACCESS_FINE_LOCATION.

Główne metody BluetoothAdapter: enable, disable, getState, getAddress

BluetoothAdapter udostępnia metody zarządzania radiem Bluetooth. enable() i disable() włączają i wyłączają Bluetooth. Obie metody wymagają uprawnienia BLUETOOTH_ADMIN i są wykonywane asynchronicznie: po wywołaniu enable() system uruchamia proces włączania radia, stan jest śledzony przez BroadcastReceiver z akcją BluetoothAdapter.ACTION_STATE_CHANGED. Od Androida 10+ enable() i disable() wymagają dodatkowego uprawnienia systemowego — zwykłe aplikacje nie mogą programowo zarządzać Bluetooth bez okna dialogowego użytkownika.

getState() zwraca bieżący stan adaptera: STATE_OFF (10), STATE_TURNING_ON (11), STATE_ON (12), STATE_TURNING_OFF (13). getAddress() zwraca adres MAC adaptera Bluetooth. Na Android 6+ do zapytania o adres MAC wymagane jest ACCESS_FINE_LOCATION (lub ACCESS_COARSE_LOCATION dla API 31+). Na Android 10+ getAddress() zwraca stały adres 02:00:00:00:00:00 — rzeczywisty adres jest niedostępny przez publiczne API.

getScanMode() określa tryb widzialności adaptera: SCAN_MODE_NONE (niewidoczny), SCAN_MODE_CONNECTABLE (widoczny dla podłączonych), SCAN_MODE_CONNECTABLE_DISCOVERABLE (widoczny dla wszystkich). Tryb widzialności jest ograniczony czasowo (zazwyczaj 60–300 sekund) dla bezpieczeństwa. Ustawienie trybu przez setScanMode() wymaga BLUETOOTH_ADMIN i uprawnienia systemowego na Android 10+.

MetodaOpisWymagane uprawnienie
enable()Włączenie radia BluetoothBLUETOOTH_ADMIN
disable()Wyłączenie radia BluetoothBLUETOOTH_ADMIN
getState()Bieżący stan adapteraBLUETOOTH
getAddress()Adres MAC adapteraBLUETOOTH + ACCESS_FINE_LOCATION (API 23+)
getScanMode()Tryb widzialności urządzeniaBLUETOOTH
setScanMode()Ustawienie trybu widzialnościBLUETOOTH_ADMIN

Skanowanie urządzeń: startDiscovery i BluetoothLeScanner

BluetoothAdapter obsługuje dwa typy skanowania. Klasyczne skanowanie Bluetooth (BR/EDR) uruchamiane jest przez startDiscovery() — wykrywa urządzenia Bluetooth wszystkich typów, w tym telefony i słuchawki. Wyniki są zwracane przez BroadcastReceiver z akcją BluetoothDevice.ACTION_FOUND. startDiscovery() działa 12 sekund i może być anulowane przez wywołanie cancelDiscovery(). Ta metoda jest przestarzała dla BLE — używaj BluetoothLeScanner.

Skanowanie BLE przez BluetoothAdapter wykonuje się przestarzałą metodą startLeScan(LeScanCallback). Od API 21 Google zaleca używanie BluetoothLeScanner, uzyskiwanego przez BluetoothAdapter.getBluetoothLeScanner(). BluetoothLeScanner udostępnia bardziej elastyczne API: konfiguracja skanowania przez ScanSettings (tryb, callback type, match mode), filtrowanie przez ScanFilter (po UUID usługi, nazwie urządzenia, adresie MAC) i obsługa PendingIntent dla skanowania w tle.

kotlin
// Stare (przestarzałe) vs nowe API skanowania BLE
import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.*

class BLEScanner(private val bluetoothAdapter: BluetoothAdapter?) {

    // PRZESTARZAŁE: startLeScan (API 18+, API 21)
    @Suppress("DEPRECATION")
    fun legacyScan() {
        bluetoothAdapter?.startLeScan { device, rssi, scanRecord ->
            print("Found (LE Scan): $device.name, RSSI: $rssi")
        }
    }

    // NOWE: BluetoothLeScanner (API 21+)
    fun modernScan() {
        val scanner = bluetoothAdapter?.bluetoothLeScanner
            ?: return

        // Ustawienia skanowania
        val settings = ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
            .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
            .build()

        // Filtruj po usłudze (UUID tętna)
        val filters = listOf(
            ScanFilter.Builder()
                .setServiceUuid(ParcelUuid.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
                .build()
        )

        // Rozpocznij skanowanie
        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")
            }
        })
    }
}

Klasa BLEScanner porównuje przestarzały startLeScan i nowoczesny BluetoothLeScanner. W legacyScan callback LeScanCallback otrzymuje BluetoothDevice, RSSI i surowy scanRecord. W modernScan używane jest ScanSettings z trybem LOW_LATENCY (maksymalna szybkość wykrywania) i ScanFilter do filtrowania po UUID usługi pulsu (Heart Rate Service 0x180D). ScanCallback udostępnia onScanResult z obiektem ScanResult zawierającym rozszerzone informacje: nazwę, RSSI, dane reklamowe, typ połączenia.

BluetoothManager: nowoczesne API dostępu do BluetoothAdapter

BluetoothManager — systemowa usługa Androida, wprowadzona w API 18 (Android 4.3), do zarządzania operacjami Bluetooth. Przed API 18 jedynym sposobem uzyskania BluetoothAdapter była statyczna metoda getDefaultAdapter(). BluetoothManager udostępnia: adapter — instancję BluetoothAdapter, getConnectedDevices() — listę podłączonych urządzeń, getDevicesMatchingConnectionStates() — filtrowanie po stanie. BluetoothManager jest także używany do uzyskania BluetoothLeScanner na starszych API.

Zalety BluetoothManager nad bezpośrednim wywołaniem BluetoothAdapter.getDefaultAdapter(): aplikacja nie zależy od statycznego singletona, menedżer uwzględnia kontekst (Activity/Application), co jest ważne w scenariuszach wielokontowych Android Enterprise. Na Android Automotive z wieloma układami Bluetooth, BluetoothManager.getAdapterList() zwraca wszystkie dostępne adaptery — BluetoothAdapter.getDefaultAdapter() zwraca tylko pierwszy.

kotlin
// Używanie BluetoothManager dla BLE
class BLEConnection(context: Context) {

    private val bluetoothManager: BluetoothManager =
        context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

    private val adapter: BluetoothAdapter? = bluetoothManager.adapter

    // Pobierz listę podłączonych urządzeń BLE
    fun getConnectedDevices(): List<BluetoothDevice> {
        return bluetoothManager.getConnectedDevices(
            BluetoothProfile.GATT
        )
    }

    // Filtruj urządzenia po stanie
    fun getDevicesByState(states: IntArray): List<BluetoothDevice> {
        return bluetoothManager.getDevicesMatchingConnectionStates(
            BluetoothProfile.GATT, states
        )
    }

    // Sprawdź obsługę BLE na urządzeniu
    fun isBLESupported(): Boolean {
        return adapter != null && context.packageManager
            .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
    }

    // Poproś o włączenie Bluetooth przez okno systemowe
    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
    }
}

Klasa BLEConnection używa BluetoothManager do dostępu do BluetoothAdapter i pobrania listy podłączonych urządzeń GATT. isBLESupported sprawdza obecność radia BLE przez PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) — ważna kontrola dla urządzeń z Bluetooth Classic bez BLE. requestEnableBluetooth wyświetla systemowe okno dialogowe włączenia Bluetooth (ACTION_REQUEST_ENABLE), nie wymagając uprawnienia BLUETOOTH_ADMIN — to jedyny legalny sposób włączenia Bluetooth na Android 10+ bez aplikacji systemowej.

Uprawnienia Androida do pracy z BluetoothAdapter

Uprawnienia dla BluetoothAdapter ewoluowały z każdą wersją Androida. Na Android 6–11 (API 23–30) do skanowania BLE wymagane są BLUETOOTH, BLUETOOTH_ADMIN i ACCESS_FINE_LOCATION. Na Android 12+ (API 31+) Google podzielił uprawnienia: ACCESS_FINE_LOCATION został zastąpiony przez BLUETOOTH_SCAN (skanowanie), BLUETOOTH_CONNECT (podłączenie), BLUETOOTH_ADVERTISE (reklama). Do wyszukiwania urządzeń BLE wystarczy BLUETOOTH_SCAN, lokalizacja nie jest wymagana.

Tabela uprawnień według wersji Androida:

OperacjaAPI 23–30API 31+
Skanowanie BLEACCESS_FINE_LOCATIONBLUETOOTH_SCAN (bez lokalizacji)
Podłączenie do BLEACCESS_FINE_LOCATIONBLUETOOTH_CONNECT
Reklama BLEACCESS_FINE_LOCATIONBLUETOOTH_ADVERTISE
Włączanie/wyłączanieBLUETOOTH_ADMINBLUETOOTH_ADMIN (systemowe)
Pobieranie adresu MACACCESS_FINE_LOCATIONBLUETOOTH_CONNECT (fikcyjny adres)

Na Android 12+ wszystkie uprawnienia Bluetooth są uprawnieniami czasu wykonania — należy je wymagać w czasie wykonania przez ActivityResultContracts.RequestMultiplePermissions. BLUETOOTH_SCAN i BLUETOOTH_ADVERTISE należą do grupy NEARBY_DEVICES, BLUETOOTH_CONNECT — do tej samej grupy. Uprawnienia BLUETOOTH i BLUETOOTH_ADMIN pozostają w manifeście dla zgodności z API < 31, ale dla API 31+ są ignorowane — Google wymaga wyraźnego określenia nowych uprawnień.

kotlin
// Prośba o uprawnienia Bluetooth na 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+: skanowanie BLE
            arrayOf(
                Manifest.permission.BLUETOOTH_SCAN,
                Manifest.permission.BLUETOOTH_CONNECT,
                Manifest.permission.BLUETOOTH_ADVERTISE
            )
        } else {
            // Android 6-11: skanowanie BLE
            arrayOf(
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.BLUETOOTH,
                Manifest.permission.BLUETOOTH_ADMIN
            )
        }
    }

    // Sprawdź wszystkie uprawnienia
    fun hasPermissions(context: Context): Boolean {
        return getRequiredPermissions().all { permission ->
            ContextCompat.checkSelfPermission(context, permission)
                    == PackageManager.PERMISSION_GRANTED
        }
    }
}

Klasa PermissionHelper zwraca poprawny zestaw uprawnień w zależności od poziomu API. Na Android 12+ używane są BLUETOOTH_SCAN, BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE bez lokalizacji. Na Android 6–11 do skanowania BLE nadal wymagane jest ACCESS_FINE_LOCATION. Deweloper musi uwzględnić oba scenariusze przy wymaganiu uprawnień przez ActivityResultContracts lub RxPermissions.

Pełny przykład pracy z BluetoothAdapter w Kotlinie

Pełny przykład aplikacji BLE w Kotlinie używającej BluetoothAdapter do skanowania, łączenia i odczytu danych z urządzenia BLE. Przykład obejmuje sprawdzanie uprawnień, pobieranie adaptera, skanowanie przez BluetoothLeScanner i łączenie przez BluetoothDevice.connectGatt.

kotlin
// Pełny menedżer BLE w Kotlinie
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. Odkrywanie usług
    fun canScan(): Boolean {
        return adapter?.isEnabled == true
                && scanner != null
                && PermissionHelper(context).hasPermissions(context)
    }

    // 2. Skanowanie z filtrem
    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. Zatrzymaj skanowanie
    fun stopScanning() {
        scanner?.stopScan(object : ScanCallback() {})
    }

    // 4. Połącz z urządzeniem 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) {
                    // Znaleziono usługi, można odczytać charakterystyki
                }
            },
            BluetoothDevice.TRANSPORT_LE
        )
    }

    // 5. Zwolnij zasoby
    fun disconnect() {
        gatt?.disconnect()
        gatt?.close()
        gatt = null
    }
}

Menedżer BLEManager łączy pełny cykl BLE na Androidzie: sprawdzenie adaptera i uprawnień (canScan), skanowanie przez BluetoothLeScanner z ScanSettings (startScanning), łączenie przez BluetoothDevice.connectGatt z TRANSPORT_LE (connectToDevice), zwalnianie zasobów (disconnect). Wszystkie operacje BLE są wykonywane na wątku UI — Android wywołuje callbacki BluetoothGattCallback na głównym wątku. Do wydajnych zadań BLE zaleca się przeniesienie operacji GATT do tła HandlerThread.

Często zadawane pytania

Czym jest BluetoothAdapter w Androidzie?

BluetoothAdapter — klasa reprezentująca lokalny adapter Bluetooth urządzenia z Androidem. Pobierana przez BluetoothManager.getAdapter() (API 18+) lub BluetoothAdapter.getDefaultAdapter(). Udostępnia metody włączania/wyłączania Bluetooth, skanowania urządzeń, zarządzania widzialnością i pobierania informacji o adapterze. Zwraca null na urządzeniach bez modułu Bluetooth.

Dlaczego BluetoothAdapter.getDefaultAdapter() zwraca null?

Przyczyną jest brak radia Bluetooth na urządzeniu. Typowe dla tabletów Wi-Fi-only, emulatora Androida i Android TV bez Bluetooth. Sprawdzaj getDefaultAdapter() na null przy uruchomieniu aplikacji i wyłączaj funkcje BLE, jeśli adapter jest nieobecny. Alternatywa — sprawdzenie przez PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) w celu dokładniejszego określenia.

Czym różni się BluetoothLeScanner od startLeScan?

BluetoothLeScanner (API 21+) — nowoczesne API do skanowania BLE z obsługą ScanFilter, ScanSettings i PendingIntent. startLeScan (API 18+) — przestarzała metoda BluetoothAdapter przyjmująca LeScanCallback z ograniczonym zestawem danych. BluetoothLeScanner jest zalecany przez Google dla wszystkich nowych projektów, umożliwia filtrowanie po UUID, konfigurację trybu zużycia energii i pracę w tle przez PendingIntent.

Jakie uprawnienia są potrzebne dla BLE na Android 12+?

Na Android 12+ (API 31) do skanowania BLE wymagane jest BLUETOOTH_SCAN, do łączenia — BLUETOOTH_CONNECT, do reklamy — BLUETOOTH_ADVERTISE. Uprawnienie do lokalizacji ACCESS_FINE_LOCATION nie jest już wymagane dla BLE. Na Android 6–11 konieczne jest ACCESS_FINE_LOCATION. Wszystkie uprawnienia są wymagane w czasie wykonania przez ActivityResultContracts.

Czy można włączyć Bluetooth programowo bez okna dialogowego?

Od Androida 10+ programowe włączenie Bluetooth bez systemowego okna dialogowego jest dostępne tylko dla aplikacji systemowych z uprawnieniem BLUETOOTH_PRIVILEGED. Zwykłe aplikacje muszą użyć Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) i startActivityForResult — użytkownik potwierdza włączenie w systemowym oknie dialogowym. BLUETOOTH_ADMIN w manifeście nie daje prawa do enable() na Android 10+.

Podsumowanie

  • BluetoothAdapter — punkt wejścia dla wszystkich operacji Bluetooth na Androidzie, pobierany przez BluetoothManager lub getDefaultAdapter()
  • getState() i isEnabled — podstawowe sprawdzenia stanu radia Bluetooth przed jakimikolwiek operacjami BLE
  • BluetoothLeScanner (API 21+) zastępuje przestarzały startLeScan z obsługą ScanFilter, ScanSettings i PendingIntent
  • BluetoothManager — nowoczesny sposób pobierania BluetoothAdapter z obsługą scenariuszy wielokontowych i Automotive
  • Uprawnienia ewoluowały: ACCESS_FINE_LOCATION (API 23-30) → BLUETOOTH_SCAN/CONNECT/ADVERTISE (API 31+)
  • enable()/disable() — na Android 10+ tylko przez systemowe okno dialogowe ACTION_REQUEST_ENABLE dla zwykłych aplikacji
  • connectGatt — metoda BluetoothDevice do ustanowienia połączenia GATT z peryferium BLE przez BluetoothGattCallback

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również