GATT — що це, Generic Attribute Profile та реалізація в Android

Автор: IT Sectr Опубліковано: 2026-07-14 Час читання: 10 хв

GATT (Generic Attribute Profile) — профіль Bluetooth Low Energy (BLE), що визначає структуру даних і правила обміну інформацією між BLE-пристроями. GATT побудований поверх Attribute Protocol (ATT) і організовує дані в ієрархію: сервіси (services), характеристики (characteristics) та дескриптори (descriptors). За даними Bluetooth SIG (2025), GATT-профіль використовується в 98% усіх BLE-застосунків — від фітнес-трекерів до розумних замків і медичних датчиків.

Головне

  • GATT — профіль BLE, що визначає структуру передачі даних через сервіси, характеристики та дескриптори
  • Ієрархія — сервіс (служба) містить характеристики, кожна характеристика — одне значення з опціональними дескрипторами
  • UUID — кожен сервіс і характеристика ідентифікуються 16-бітним (стандартні) або 128-бітним (кастомні) UUID
  • Ролі — GATT Server (надає дані) та GATT Client (читає/записує дані)
  • Android API — BluetoothGatt, BluetoothGattService, BluetoothGattCharacteristic — основні класи для роботи з GATT

Що таке GATT?

GATT (Generic Attribute Profile) — це профіль Bluetooth Low Energy (BLE), який визначає, як два BLE-пристрої обмінюються даними через Attribute Protocol (ATT). GATT стандартизує структуру даних: усі дані організовані в ієрархію «сервіс → характеристика → дескриптор». Профіль був представлений у специфікації Bluetooth 4.0 (2010) разом із BLE і з того часу залишається основним механізмом передачі даних для енергоефективних Bluetooth-пристроїв. На відміну від класичного Bluetooth, де дані передаються через послідовний порт (SPP), GATT надає структурований доступ до даних через операції читання, запису та сповіщень.

Роль GATT у стеку BLE

BLE-стек складається з кількох рівнів: Physical Layer (радіо), Link Layer (керування з'єднанням), L2CAP (логічна канальна передача), ATT (Attribute Protocol — доступ до атрибутів) і GATT (профіль на основі ATT). GATT — найвищий рівень, з яким працює розробник застосунку. Нижчий ATT надає базові операції: читання, запис, сповіщення та індикацію атрибутів. GATT додає семантику: визначає, що таке сервіс, характеристика, як вони групуються та які правила діють при їх читанні та записі. За даними Bluetooth Core Specification 5.4 (2023), GATT підтримує до 65 535 атрибутів (сервісів + характеристик + дескрипторів) на одному пристрої.

Архітектура GATT: сервіси, характеристики та дескриптори

GATT-ієрархія складається з трьох рівнів. Сервіс (Service) — логічна група характеристик, що вирішує одне завдання (наприклад, «Сервіс батареї» або «Сервіс Heart Rate»). Характеристика (Characteristic) — це одиниця даних з відомим типом: поточний рівень заряду, покази датчика, стан перемикача. Кожна характеристика має значення (value) та один або кілька дескрипторів (Descriptors), що описують метадані: одиниці вимірювання, налаштування сповіщень, діапазон значень. UUID (Universally Unique Identifier) однозначно ідентифікує кожен сервіс і кожну характеристику.

Типи операцій з характеристиками

GATT підтримує чотири типи операцій для взаємодії з характеристиками. Read — клієнт запитує поточне значення характеристики у сервера. Write — клієнт надсилає нове значення на сервер. Notify — сервер надсилає значення клієнту без підтвердження (швидший, але менш надійний спосіб). Indicate — сервер надсилає значення з підтвердженням отримання (надійніше, але повільніше). Розробник обирає тип залежно від сценарію: для показів датчика пульсу достатньо Notify, для запису конфігурації розумного замка — Write з підтвердженням.

kotlin
// Структура даних GATT у коді Android
data class BleService(
    val uuid: UUID,
    val characteristics: List<BleCharacteristic>
)

data class BleCharacteristic(
    val uuid: UUID,
    val properties: Int, // READ, WRITE, NOTIFY, INDICATE
    val descriptors: List<BleDescriptor>,
    var value: ByteArray?
)

GATT і GAP: відмінності профілів BLE

У специфікації BLE визначено два основні профілі: GAP (Generic Access Profile) і GATT (Generic Attribute Profile). GAP відповідає за виявлення пристроїв, встановлення з'єднання та керування видимістю — це «мережевий рівень» BLE. GATT — за обмін даними після встановлення з'єднання, тобто «прикладний рівень». Розробник використовує GAP для сканування та підключення до пристрою, а GATT — для читання, запису та отримання сповіщень від підключеного пристрою.

ХарактеристикаGAPGATT
ПризначенняВиявлення та підключенняОбмін даними
РоліCentral / PeripheralClient / Server
ПротоколHCI, Link LayerATT (Attribute Protocol)
ЕтапДо підключенняПісля підключення
Основний класBluetoothAdapterBluetoothGatt

Ролі в GATT

GATT визначає дві ролі: GATT Server і GATT Client. Сервер — пристрій, який надає дані (наприклад, фітнес-трекер, що передає покази пульсу). Клієнт — пристрій, який запитує дані (наприклад, смартфон, що читає покази). У більшості сценаріїв Android-застосунок виступає GATT Client, а BLE-периферія — GATT Server. Однак Android також може бути GATT Server — наприклад, якщо застосунок емулює BLE-пристрій для інших пристроїв. Роль визначається на етапі встановлення GATT-з'єднання і не змінюється протягом сесії.

Як працює GATT-комунікація в BLE

Процес GATT-комунікації починається після встановлення BLE-з'єднання між пристроями. Спочатку GATT Client виявляє сервіси на GATT Server через операцію Service Discovery — Android виконує її автоматично при підключенні через BluetoothGatt.discoverServices(). Після виявлення клієнт отримує список доступних сервісів, характеристик і дескрипторів. Потім клієнт може читати значення характеристик (Read), записувати нові значення (Write) або підписуватися на сповіщення (Set Notify/Indicate). GATT Server може надсилати Notify/Indicate клієнту в будь-який момент після встановлення з'єднання.

MTU — максимальний розмір пакета

За замовчуванням розмір одного GATT-пакета (MTU, Maximum Transmission Unit) у BLE становить 23 байти, з яких 3 байти — заголовок ATT, і 20 байтів — корисні дані. Якщо застосунку потрібно передати більше даних (наприклад, OTA-оновлення прошивки), можна запросити збільшення MTU до 517 байтів через requestMtu() в Android. Збільшений MTU скорочує кількість пакетів для передачі одного блоку даних — замість 50 маленьких пакетів можна відправити 2 великих, що знижує енергоспоживання та прискорює передачу. Максимальний MTU залежить від версії BLE та можливостей чипа — Bluetooth 5.0 підтримує до 517 байтів, старіші версії — до 247 байтів.

kotlin
// Підписатися на сповіщення характеристик
fun enableNotifications(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
    gatt.setCharacteristicNotification(characteristic, true)

    // Увімкнути CCCD (Client Characteristic Configuration Descriptor)
    val cccdUuid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
    val descriptor = characteristic.getDescriptor(cccdUuid)
    descriptor?.let {
        it.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)
        gatt.writeDescriptor(it)
    }
}

Обробка сповіщень

Для отримання сповіщень від GATT Server у Android необхідно реалізувати колбек BluetoothGattCallback.onCharacteristicChanged(). У цьому методі застосунок отримує оновлене значення характеристики кожного разу, коли сервер надсилає Notify або Indicate. Для обробки даних у реальному часі використовуйте буфер і корутини Kotlin — це дозволить не блокувати UI-потік при інтенсивних сповіщеннях (наприклад, 100+ показів пульсу за секунду). При індикаціях (Indicate) обов'язково викликайте gatt.sendResponse() на стороні сервера — в Android-клієнті це обробляється автоматично.

Реалізація GATT на Android

На Android робота з GATT реалізується через класи пакета android.bluetooth: BluetoothGatt (з'єднання), BluetoothGattService (сервіс), BluetoothGattCharacteristic (характеристика) та BluetoothGattDescriptor (дескриптор). Підключення до BLE-пристрою починається з виклику BluetoothDevice.connectGatt() — цей метод повертає BluetoothGatt, через який виконуються всі подальші операції. Всі GATT-колбеки приходять у BluetoothGattCallback — це асинхронний інтерфейс, що викликається в тому ж потоці, де був створений BluetoothGatt. Важливо: всі операції GATT повинні виконуватися послідовно — одночасний виклик кількох операцій на одному BluetoothGatt призводить до помилок.

Життєвий цикл GATT-з'єднання

Правильне керування життєвим циклом GATT-з'єднання критичне для стабільності BLE-застосунку. Після виклику connectGatt() застосунок очікує колбек onConnectionStateChange() зі станом STATE_CONNECTED. Потім система автоматично запускає Service Discovery, після завершення якого викликається onServicesDiscovered(). Тільки після цього можна виконувати читання, запис і підписку. При завершенні роботи обов'язково викличте gatt.close() в onDestroy() або onPause() — незакриті GATT-з'єднання споживають батарею та можуть блокувати повторне підключення до того ж пристрою на Android.

kotlin
// Підключитися до BLE-пристрою через GATT
private val gattCallback = 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) {
        val service = gatt.getService(UUID.fromString("180D"))
        val characteristic = service?.getCharacteristic(
            UUID.fromString("2A37")
        )
        characteristic?.let { enableNotifications(gatt, it) }
    }
}

Стандартні GATT-профілі та сервіси

Bluetooth SIG (Special Interest Group) визначає десятки стандартних GATT-профілів і сервісів із фіксованими 16-бітними UUID. Найпоширеніші: сервіс Battery Service (UUID 180F, характеристика Battery Level 2A19), сервіс Heart Rate (UUID 180D, характеристика Heart Rate Measurement 2A37), сервіс Device Information (UUID 180A, характеристики Manufacturer Name, Serial Number). Використання стандартних сервісів гарантує сумісність між пристроями різних виробників — будь-який фітнес-браслет із сервісом Heart Rate повинен працювати з будь-яким Android-застосунком, який його підтримує.

Проєктування кастомних GATT-сервісів

Якщо стандартні сервіси не покривають завдання, розробник може створити власні GATT-сервіси з 128-бітними UUID (кастомні UUID). При проєктуванні кастомного сервісу потрібно: визначити логічну групу характеристик (наприклад, «Сервіс керування замком»), задати кожній характеристиці правильні властивості (Read, Write, Notify), визначити допустимі значення та одиниці вимірювання через дескриптор Characteristic Presentation Format. Для складних протоколів рекомендується включати в сервіс характеристику Command із Write-властивістю та характеристику Status із Notify — це відповідає шаблону Command/Status, прийнятому в промислових BLE-застосунках.

kotlin
// Створити кастомний GATT-сервіс (Android як GATT Server)
private fun createCustomService(): BluetoothGattService {
    val serviceUuid = UUID.fromString("12345678-1234-5678-1234-56789abcdef0")
    val service = BluetoothGattService(
        serviceUuid, BluetoothGattService.SERVICE_TYPE_PRIMARY
    )

    val charUuid = UUID.fromString("12345678-1234-5678-1234-56789abcdef1")
    val characteristic = BluetoothGattCharacteristic(
        charUuid,
        BluetoothGattCharacteristic.PROPERTY_READ or
        BluetoothGattCharacteristic.PROPERTY_NOTIFY,
        BluetoothGattCharacteristic.PERMISSION_READ
    )
    service.addCharacteristic(characteristic)
    return service
}

Часті запитання

Що таке GATT у BLE і навіщо він потрібен?

GATT (Generic Attribute Profile) — це профіль Bluetooth Low Energy, що визначає структуру обміну даними між пристроями. Він потрібен для стандартизації доступу до інформації: всі BLE-пристрої організовують дані в сервіси та характеристики, що дозволяє будь-якому клієнту читати покази датчиків, керувати пристроями та отримувати сповіщення.

Чим GATT відрізняється від GAP?

GAP відповідає за виявлення та підключення BLE-пристроїв (сканування, реклама, встановлення з'єднання). GATT — за обмін даними після підключення (читання, запис, сповіщення). GAP працює до з'єднання, GATT — після. Обидва профілі обов'язкові для BLE, але виконують різні функції: GAP — «мережевий рівень», GATT — «прикладний».

Які існують GATT-сервіси та характеристики?

Стандартні сервіси включають Battery Service (180F, рівень заряду), Heart Rate (180D, пульс), Device Information (180A, дані пристрою). Кожен сервіс містить кілька характеристик із 16-бітними UUID. Розробники можуть створювати кастомні сервіси з 128-бітними UUID для специфічних завдань — наприклад, керування розумним замком або передачі даних фітнес-трекера.

Як працює GATT на Android?

На Android GATT реалізується через BluetoothGatt (з'єднання), BluetoothGattService (сервіс), BluetoothGattCharacteristic (характеристика) та BluetoothGattDescriptor (дескриптор). Підключення виконується через connectGatt(), після чого в колбеці BluetoothGattCallback приходять події: onConnectionStateChange, onServicesDiscovered, onCharacteristicChanged (для сповіщень). Всі GATT-операції повинні виконуватися послідовно.

Що таке UUID у GATT?

UUID (Universally Unique Identifier) — 16-бітний або 128-бітний ідентифікатор, що однозначно визначає сервіс або характеристику в GATT. Стандартні сервіси Bluetooth SIG використовують 16-бітні UUID (наприклад, 180D для Heart Rate). Кастомні сервіси розробників — 128-бітні UUID (наприклад, 12345678-1234-5678-1234-56789abcdef0). UUID дозволяє клієнту знайти потрібні дані на GATT Server.

Підсумки

  • GATT — профіль BLE для структурованого обміну даними через ієрархію сервісів, характеристик і дескрипторів, заснований на Attribute Protocol (ATT)
  • Ієрархія даних — сервіс (логічна група), характеристика (конкретне значення з типом), дескриптор (метадані — одиниці, налаштування сповіщень)
  • Ролі GATT — Server (надає дані, зазвичай BLE-периферія) та Client (читає/записує, зазвичай Android-смартфон)
  • Операції — Read, Write, Notify (без підтвердження, швидше) та Indicate (з підтвердженням, надійніше); вибір залежить від сценарію
  • Android API — BluetoothGatt, BluetoothGattCallback, BluetoothGattService, BluetoothGattCharacteristic; послідовні асинхронні виклики через колбеки
  • Стандартні профілі — Battery Service, Heart Rate, Device Information — забезпечують сумісність між пристроями різних виробників
  • Кастомні сервіси — 128-бітні UUID для унікальних завдань; проєктуються за шаблоном Command/Status із правильними властивостями (Read, Write, Notify, Indicate)

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також