BluetoothAdapter — шта је то, методе и управљање Bluetooth-ом у Андроиду

Аутор: IT Sectr Објављено: 2026-07-16 Време читања: 10 мин

BluetoothAdapter — системска класа Андроида која представља локални Bluetooth-адаптер уређаја. BluetoothAdapter је улазна тачка за све Bluetooth-операције на Андроиду: укључивање радија (enable), скенирање уређаја, управљање видљивошћу (setScanMode), добијање информација о адаптеру (getName, getAddress, getState). Класа је доступна преко BluetoothManager.getAdapter() (API 18+) или BluetoothAdapter.getDefaultAdapter(). На уређајима без Bluetooth-модула getDefaultAdapter() враћа null. Према Android Developers, 2026, BluetoothAdapter је обавезна компонента за сваку BLE-апликацију на Андроиду, почев од API 5.

Главно

  • BluetoothAdapter — системска класа Андроида за управљање локалним 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-апликације на Андроиду. Препоручени метод — преко 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
// Стари (застарели) vs нови 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 — системски сервис Андроида, уведен у 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+ без системске апликације.

Дозволе Андроида за рад са BluetoothAdapter-ом

Дозволе за BluetoothAdapter су еволуирале са сваком верзијом Андроида. На 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, локација није потребна.

Табела дозвола по верзијама Андроида:

Операција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-дозволе су runtime дозволе — треба их захтевати у рантајму преко 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-циклус на Андроиду: проверу адаптера и дозвола (canScan), скенирање преко BluetoothLeScanner-а са ScanSettings (startScanning), повезивање преко BluetoothDevice.connectGatt са TRANSPORT_LE (connectToDevice), ослобађање ресурса (disconnect). Све BLE-операције се извршавају на UI нити — Android позива callback-ове BluetoothGattCallback на главној нити. За продуктивне BLE-задатке препоручује се пребацивање GATT-операција у позадинску HandlerThread нит.

Често постављана питања

Шта је BluetoothAdapter у Андроиду?

BluetoothAdapter — класа која представља локални Bluetooth-адаптер Android-уређаја. Добија се преко BluetoothManager.getAdapter() (API 18+) или BluetoothAdapter.getDefaultAdapter(). Пружа методе укључивања/искључивања Bluetooth-а, скенирања уређаја, управљања видљивошћу и добијања информација о адаптеру. Враћа null на уређајима без Bluetooth-модула.

Зашто BluetoothAdapter.getDefaultAdapter() враћа null?

Разлог — одсуство Bluetooth-радија на уређају. Карактеристично за Wi-Fi-only таблете, емулатор Андроида и 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-операције на Андроиду, добија се преко 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. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође