BluetoothAdapter — какво е, методи и управление на Bluetooth в Android

Автор: IT Sectr Публикувано: 2026-07-16 Време за четене: 10 мин

BluetoothAdapter — системният клас на Android, представляващ локалния Bluetooth адаптер на устройството. BluetoothAdapter е входната точка за всички Bluetooth операции в Android: включване на радиото (enable), сканиране на устройства, управление на видимостта (setScanMode), получаване на информация за адаптера (getName, getAddress, getState). Класът е достъпен чрез BluetoothManager.getAdapter() (API 18+) или BluetoothAdapter.getDefaultAdapter(). На устройства без Bluetooth модул getDefaultAdapter() връща null. Според Android Developers, 2026, BluetoothAdapter е задължителен компонент за всяко BLE приложение в Android, започвайки от API 5.

Основни моменти

  • BluetoothAdapter — системен клас на Android за управление на локалния Bluetooth адаптер на устройството
  • getDefaultAdapter() — статичен метод за получаване на инстанция; връща null на устройства без Bluetooth
  • getBluetoothLeScanner() — метод за достъп до модерния BLE скенер (API 21+)
  • enable/disable — методи за включване и изключване на Bluetooth радиото (изискват разрешение BLUETOOTH_ADMIN)
  • startDiscovery/startLeScan — методи за класическо и BLE сканиране (LE Scan е остарял, използвайте BluetoothLeScanner)

Какво е BluetoothAdapter: същност и получаване на инстанция

BluetoothAdapter представлява физическия Bluetooth адаптер на Android устройството. Всяко устройство има точно един адаптер (изключение — Android Automotive с няколко Bluetooth чипа, където се използва BluetoothManager.getAdapterList()). BluetoothAdapter капсулира състоянието на радиото: STATE_OFF (0), STATE_TURNING_ON (1), STATE_ON (2), STATE_TURNING_OFF (3). Състоянието се проследява чрез BroadcastReceiver на ACTION_STATE_CHANGED.

Получаването на инстанция на BluetoothAdapter е първата стъпка на всяко BLE приложение в Android. Препоръчителният метод — чрез BluetoothManager.getAdapter() от API 18+. Алтернатива — статичният метод BluetoothAdapter.getDefaultAdapter(), който работи от API 5, но е по-малко гъвкав. И двата метода връщат null, ако устройството няма Bluetooth модул (Wi-Fi-only таблети, емулатор). Проверката за null е задължителна: приложението трябва правилно да приключи или да деактивира BLE функциите.

kotlin
// Получаване на BluetoothAdapter (препоръчително)
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context

class BluetoothHelper(context: Context) {

    private val bluetoothAdapter: BluetoothAdapter?

    init {
        // Метод 1: чрез BluetoothManager (API 18+)
        val manager = context.getSystemService(Context.BLUETOOTH_SERVICE)
                as BluetoothManager?
        bluetoothAdapter = manager?.adapter

        // Метод 2: чрез статичен метод (API 5+)
        // val adapter = BluetoothAdapter.getDefaultAdapter()

        // Проверка за null
        if (bluetoothAdapter == null) {
            // Устройството не поддържа Bluetooth
        }
    }

    // Проверете състоянието на Bluetooth
    fun isBluetoothEnabled(): Boolean {
        return bluetoothAdapter?.isEnabled == true
    }

    // Получете информация за адаптера
    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")
        )
    }
}

Класът BluetoothHelper демонстрира получаване на BluetoothAdapter чрез BluetoothManager с последваща проверка за null. isBluetoothEnabled проверява isEnabled — задължително условие преди каквито и да било BLE операции. getAdapterInfo връща името на устройството, MAC адреса, състоянието и режима на видимост. Важно: на Android 10+ (API 29+) системната услуга връща фалшив MAC адрес (02:00:00:00:00:00), ако приложението няма разрешение BLUETOOTH_ADMIN и ACCESS_FINE_LOCATION.

Основни методи на BluetoothAdapter: enable, disable, getState, getAddress

BluetoothAdapter предоставя методи за управление на Bluetooth радиото. enable() и disable() включват и изключват Bluetooth. И двата метода изискват разрешение BLUETOOTH_ADMIN и се изпълняват асинхронно: след извикване на enable() системата стартира процес на включване на радиото, състоянието се проследява чрез BroadcastReceiver с действие BluetoothAdapter.ACTION_STATE_CHANGED. От Android 10+ enable() и disable() изискват допълнително системно разрешение — обикновените приложения не могат програмно да управляват Bluetooth без диалогов прозорец на потребителя.

getState() връща текущото състояние на адаптера: STATE_OFF (10), STATE_TURNING_ON (11), STATE_ON (12), STATE_TURNING_OFF (13). getAddress() връща MAC адреса на Bluetooth адаптера. На Android 6+ за заявка на MAC адрес е необходим ACCESS_FINE_LOCATION (или ACCESS_COARSE_LOCATION за API 31+). На Android 10+ getAddress() връща постоянен адрес 02:00:00:00:00:00 — реалният адрес не е достъпен чрез публичното API.

getScanMode() определя режима на видимост на адаптера: SCAN_MODE_NONE (невидим), SCAN_MODE_CONNECTABLE (видим за свързани), SCAN_MODE_CONNECTABLE_DISCOVERABLE (видим за всички). Режимът на видимост е ограничен във времето (обикновено 60–300 секунди) за сигурност. Настройването на режима чрез setScanMode() изисква BLUETOOTH_ADMIN и системно разрешение на Android 10+.

МетодОписаниеИзисквано разрешение
enable()Включване на Bluetooth радиоBLUETOOTH_ADMIN
disable()Изключване на Bluetooth радиоBLUETOOTH_ADMIN
getState()Текущо състояние на адаптераBLUETOOTH
getAddress()MAC адрес на адаптераBLUETOOTH + ACCESS_FINE_LOCATION (API 23+)
getScanMode()Режим на видимост на устройствотоBLUETOOTH
setScanMode()Настройване на режима на видимостBLUETOOTH_ADMIN

Сканиране на устройства: startDiscovery и BluetoothLeScanner

BluetoothAdapter поддържа два типа сканиране. Класическото Bluetooth сканиране (BR/EDR) се стартира чрез startDiscovery() — открива Bluetooth устройства от всички типове, включително телефони и слушалки. Резултатите се връщат чрез BroadcastReceiver с действие BluetoothDevice.ACTION_FOUND. startDiscovery() работи 12 секунди и може да бъде отменен чрез извикване на cancelDiscovery(). Този метод е остарял за BLE — използвайте BluetoothLeScanner.

BLE сканирането чрез BluetoothAdapter се изпълнява с остарелия метод startLeScan(LeScanCallback). От API 21 Google препоръчва използването на BluetoothLeScanner, получен чрез BluetoothAdapter.getBluetoothLeScanner(). BluetoothLeScanner предоставя по-гъвкаво API: конфигуриране на сканирането чрез ScanSettings (режим, callback type, match mode), филтриране чрез ScanFilter (по UUID на услугата, име на устройството, MAC адрес) и поддръжка на PendingIntent за фоново сканиране.

kotlin
// Старо (остаряло) срещу ново BLE API за сканиране
import android.bluetooth.BluetoothAdapter
import android.bluetooth.le.*

class BLEScanner(private val bluetoothAdapter: BluetoothAdapter?) {

    // ОСТАРЯЛО: startLeScan (API 18+, API 21)
    @Suppress("DEPRECATION")
    fun legacyScan() {
        bluetoothAdapter?.startLeScan { device, rssi, scanRecord ->
            print("Found (LE Scan): $device.name, RSSI: $rssi")
        }
    }

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

        // Настройки на сканиране
        val settings = ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
            .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
            .build()

        // Филтриране по услуга (UUID на пулс)
        val filters = listOf(
            ScanFilter.Builder()
                .setServiceUuid(ParcelUuid.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
                .build()
        )

        // Стартиране на сканиране
        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")
            }
        })
    }
}

Класът BLEScanner сравнява остарелия startLeScan и модерния BluetoothLeScanner. В legacyScan callbackът LeScanCallback получава BluetoothDevice, RSSI и суров scanRecord. В modernScan се използва ScanSettings с режим LOW_LATENCY (максимална скорост на откриване) и ScanFilter за филтриране по UUID на услугата за пулс (Heart Rate Service 0x180D). ScanCallback предоставя onScanResult с обект ScanResult, съдържащ разширена информация: име, RSSI, рекламни данни, тип на връзката.

BluetoothManager: модерно API за достъп до BluetoothAdapter

BluetoothManager — системната услуга на Android, въведена в API 18 (Android 4.3), за управление на Bluetooth операции. Преди API 18 единственият начин за получаване на BluetoothAdapter беше статичният метод getDefaultAdapter(). BluetoothManager предоставя: adapter — инстанция на BluetoothAdapter, getConnectedDevices() — списък на свързани устройства, getDevicesMatchingConnectionStates() — филтриране по състояние. BluetoothManager се използва също за получаване на BluetoothLeScanner на стари API.

Предимства на BluetoothManager пред директното извикване на BluetoothAdapter.getDefaultAdapter(): приложението не зависи от статичен сингълтън, мениджърът взема предвид контекста (Activity/Application), което е важно за мултиакаунт сценарии в Android Enterprise. На Android Automotive с няколко Bluetooth чипа BluetoothManager.getAdapterList() връща всички налични адаптери — BluetoothAdapter.getDefaultAdapter() връща само първия.

kotlin
// Използване на BluetoothManager за BLE
class BLEConnection(context: Context) {

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

    private val adapter: BluetoothAdapter? = bluetoothManager.adapter

    // Получаване на списък със свързани BLE устройства
    fun getConnectedDevices(): List<BluetoothDevice> {
        return bluetoothManager.getConnectedDevices(
            BluetoothProfile.GATT
        )
    }

    // Филтриране на устройства по състояние
    fun getDevicesByState(states: IntArray): List<BluetoothDevice> {
        return bluetoothManager.getDevicesMatchingConnectionStates(
            BluetoothProfile.GATT, states
        )
    }

    // Проверете поддръжката на BLE на устройството
    fun isBLESupported(): Boolean {
        return adapter != null && context.packageManager
            .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
    }

    // Поискайте включване на Bluetooth чрез системен диалог
    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
    }
}

Класът BLEConnection използва BluetoothManager за достъп до BluetoothAdapter и получаване на списък със свързани GATT устройства. isBLESupported проверява наличието на BLE радио чрез PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) — важна проверка за устройства с Bluetooth Classic без BLE. requestEnableBluetooth показва системен диалог за включване на Bluetooth (ACTION_REQUEST_ENABLE), без да изисква разрешение BLUETOOTH_ADMIN — това е единственият легален начин за включване на Bluetooth на Android 10+ без системно приложение.

Разрешения на Android за работа с BluetoothAdapter

Разрешенията за BluetoothAdapter са еволюирали с всяка версия на Android. На Android 6–11 (API 23–30) за BLE сканиране са задължителни BLUETOOTH, BLUETOOTH_ADMIN и ACCESS_FINE_LOCATION. На Android 12+ (API 31+) Google раздели разрешенията: ACCESS_FINE_LOCATION беше заменен с BLUETOOTH_SCAN (сканиране), BLUETOOTH_CONNECT (свързване), BLUETOOTH_ADVERTISE (рекламиране). За търсене на BLE устройства BLUETOOTH_SCAN е достатъчен, местоположение не се изисква.

Таблица на разрешенията по версии на Android:

ОперацияAPI 23–30API 31+
BLE сканиранеACCESS_FINE_LOCATIONBLUETOOTH_SCAN (без местоположение)
Свързване с BLEACCESS_FINE_LOCATIONBLUETOOTH_CONNECT
BLE рекламиранеACCESS_FINE_LOCATIONBLUETOOTH_ADVERTISE
Включване/изключванеBLUETOOTH_ADMINBLUETOOTH_ADMIN (системно)
Получаване на MAC адресACCESS_FINE_LOCATIONBLUETOOTH_CONNECT (фалшив адрес)

На Android 12+ всички Bluetooth разрешения са разрешения по време на изпълнение — трябва да се искат по време на изпълнение чрез ActivityResultContracts.RequestMultiplePermissions. BLUETOOTH_SCAN и BLUETOOTH_ADVERTISE принадлежат към групата NEARBY_DEVICES, BLUETOOTH_CONNECT — към същата група. Разрешенията BLUETOOTH и BLUETOOTH_ADMIN остават в манифеста за съвместимост с API < 31, но за API 31+ се игнорират — Google изисква изрично посочване на новите разрешения.

kotlin
// Искане на Bluetooth разрешения на 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
            )
        }
    }

    // Проверете всички разрешения
    fun hasPermissions(context: Context): Boolean {
        return getRequiredPermissions().all { permission ->
            ContextCompat.checkSelfPermission(context, permission)
                    == PackageManager.PERMISSION_GRANTED
        }
    }
}

Класът PermissionHelper връща правилния набор от разрешения в зависимост от нивото на API. На Android 12+ се използват BLUETOOTH_SCAN, BLUETOOTH_CONNECT, BLUETOOTH_ADVERTISE без местоположение. На Android 6–11 за BLE сканиране все още е необходим ACCESS_FINE_LOCATION. Разработчикът трябва да вземе предвид и двата сценария при искане на разрешения чрез ActivityResultContracts или RxPermissions.

Пълен пример за работа с BluetoothAdapter в Kotlin

Пълен пример на BLE приложение в Kotlin, използващо BluetoothAdapter за сканиране, свързване и четене на данни от BLE устройство. Примерът обхваща проверка на разрешения, получаване на адаптер, сканиране чрез BluetoothLeScanner и свързване чрез BluetoothDevice.connectGatt.

kotlin
// Пълен BLE мениджър в 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. Откриване на услуги
    fun canScan(): Boolean {
        return adapter?.isEnabled == true
                && scanner != null
                && PermissionHelper(context).hasPermissions(context)
    }

    // 2. Сканиране с филтър
    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. Спиране на сканиране
    fun stopScanning() {
        scanner?.stopScan(object : ScanCallback() {})
    }

    // 4. Свързване с 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) {
                    // Услугите са намерени, могат да се четат характеристики
                }
            },
            BluetoothDevice.TRANSPORT_LE
        )
    }

    // 5. Освобождаване на ресурси
    fun disconnect() {
        gatt?.disconnect()
        gatt?.close()
        gatt = null
    }
}

Мениджърът BLEManager обединява пълния BLE цикъл в Android: проверка на адаптер и разрешения (canScan), сканиране чрез BluetoothLeScanner с ScanSettings (startScanning), свързване чрез BluetoothDevice.connectGatt с TRANSPORT_LE (connectToDevice), освобождаване на ресурси (disconnect). Всички BLE операции се изпълняват на UI нишката — Android извиква callback-ите BluetoothGattCallback на основната нишка. За производителни BLE задачи се препоръчва преместване на GATT операциите във фонова HandlerThread нишка.

Често задавани въпроси

Какво е BluetoothAdapter в Android?

BluetoothAdapter — клас, представляващ локалния Bluetooth адаптер на Android устройството. Получава се чрез BluetoothManager.getAdapter() (API 18+) или BluetoothAdapter.getDefaultAdapter(). Предоставя методи за включване/изключване на Bluetooth, сканиране на устройства, управление на видимостта и получаване на информация за адаптера. Връща null на устройства без Bluetooth модул.

Защо BluetoothAdapter.getDefaultAdapter() връща null?

Причината — липса на Bluetooth радио на устройството. Характерно за Wi-Fi-only таблети, емулатор на Android и Android TV без Bluetooth. Проверявайте getDefaultAdapter() за null при стартиране на приложението и деактивирайте BLE функциите, ако адаптерът липсва. Алтернатива — проверка чрез PackageManager.hasSystemFeature(FEATURE_BLUETOOTH_LE) за по-точно определяне.

Как се различава BluetoothLeScanner от startLeScan?

BluetoothLeScanner (API 21+) — модерно API за BLE сканиране с поддръжка на ScanFilter, ScanSettings и PendingIntent. startLeScan (API 18+) — остарял метод на BluetoothAdapter, приемащ LeScanCallback с ограничен набор от данни. BluetoothLeScanner се препоръчва от Google за всички нови проекти, позволява филтриране по UUID, конфигуриране на режим на консумация на енергия и работа във фонов режим чрез PendingIntent.

Какви разрешения са необходими за BLE на Android 12+?

На Android 12+ (API 31) за BLE сканиране е необходимо BLUETOOTH_SCAN, за свързване — BLUETOOTH_CONNECT, за рекламиране — BLUETOOTH_ADVERTISE. Разрешението за местоположение ACCESS_FINE_LOCATION вече не е необходимо за BLE. На Android 6–11 е необходим ACCESS_FINE_LOCATION. Всички разрешения се искат по време на изпълнение чрез ActivityResultContracts.

Може ли Bluetooth да се включи програмно без диалог?

От Android 10+ програмното включване на Bluetooth без системен диалог е достъпно само за системни приложения с разрешение BLUETOOTH_PRIVILEGED. Обикновените приложения трябва да използват Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) и startActivityForResult — потребителят потвърждава включването в системния диалог. BLUETOOTH_ADMIN в манифеста не дава право на enable() на Android 10+.

Заключение

  • BluetoothAdapter — входна точка за всички Bluetooth операции в Android, получава се чрез BluetoothManager или getDefaultAdapter()
  • getState() и isEnabled — основни проверки на състоянието на Bluetooth радиото преди каквито и да било BLE операции
  • BluetoothLeScanner (API 21+) заменя остарелия startLeScan с поддръжка на ScanFilter, ScanSettings и PendingIntent
  • BluetoothManager — модерен начин за получаване на BluetoothAdapter с поддръжка на мултиакаунт сценарии и Automotive
  • Разрешенията са еволюирали: ACCESS_FINE_LOCATION (API 23-30) → BLUETOOTH_SCAN/CONNECT/ADVERTISE (API 31+)
  • enable()/disable() — на Android 10+ само чрез системен диалог ACTION_REQUEST_ENABLE за обикновени приложения
  • connectGatt — метод на BluetoothDevice за установяване на GATT връзка с BLE периферия чрез BluetoothGattCallback

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също