GATT — cos'è, Generic Attribute Profile e implementazione in Android

Autore: IT Sectr Pubblicato: 2026-07-14 Tempo di lettura: 10 min

GATT (Generic Attribute Profile) è un profilo Bluetooth Low Energy (BLE) che definisce la struttura dei dati e le regole di scambio di informazioni tra dispositivi BLE. GATT è costruito sopra l'Attribute Protocol (ATT) e organizza i dati in una gerarchia: servizi, caratteristiche e descrittori. Secondo Bluetooth SIG (2025), il profilo GATT è utilizzato nel 98% di tutte le applicazioni BLE — dai fitness tracker alle serrature intelligenti e ai sensori medici.

Punti chiave

  • GATT — un profilo BLE che definisce la struttura di trasferimento dati attraverso servizi, caratteristiche e descrittori
  • Gerarchia — un servizio contiene caratteristiche, ogni caratteristica ha un valore con descrittori opzionali
  • UUID — ogni servizio e caratteristica è identificato da un UUID a 16 bit (standard) o 128 bit (personalizzato)
  • Ruoli — Server GATT (fornisce dati) e Client GATT (legge/scrive dati)
  • API Android — BluetoothGatt, BluetoothGattService, BluetoothGattCharacteristic — classi principali per lavorare con GATT

Cos'è GATT?

GATT (Generic Attribute Profile) è un profilo Bluetooth Low Energy (BLE) che definisce come due dispositivi BLE scambiano dati attraverso l'Attribute Protocol (ATT). GATT standardizza la struttura dei dati: tutti i dati sono organizzati in una gerarchia “servizio → caratteristica → descrittore”. Il profilo è stato introdotto nella specifica Bluetooth 4.0 (2010) insieme a BLE e da allora rimane il meccanismo principale di trasferimento dati per dispositivi Bluetooth a basso consumo. A differenza del Bluetooth classico, dove i dati vengono trasmessi attraverso una porta seriale (SPP), GATT fornisce un accesso strutturato ai dati attraverso operazioni di lettura, scrittura e notifica.

Il ruolo di GATT nello stack BLE

Lo stack BLE è composto da diversi livelli: Livello Fisico (radio), Livello Collegamento (gestione connessione), L2CAP (controllo canale logico), ATT (Attribute Protocol — accesso agli attributi) e GATT (profilo basato su ATT). GATT è il livello più alto con cui lavorano gli sviluppatori di applicazioni. L'ATT sottostante fornisce operazioni di base: lettura, scrittura, notifica e indicazione degli attributi. GATT aggiunge semantica: definisce cosa sono un servizio e una caratteristica, come sono raggruppati e quali regole si applicano durante la lettura e scrittura. Secondo la Bluetooth Core Specification 5.4 (2023), GATT supporta fino a 65.535 attributi (servizi + caratteristiche + descrittori) su un singolo dispositivo.

Architettura GATT: servizi, caratteristiche e descrittori

La gerarchia GATT è composta da tre livelli. Un Servizio è un gruppo logico di caratteristiche che risolve un compito (ad esempio, “Servizio Batteria” o “Servizio Frequenza Cardiaca”). Una Caratteristica è un'unità di dati con un tipo noto: livello batteria attuale, lettura sensore, stato interruttore. Ogni caratteristica ha un valore e uno o più Descrittori che descrivono metadati: unità di misura, impostazioni di notifica, intervallo di valori. UUID (Identificatore Univoco Universale) identifica in modo univoco ogni servizio e ogni caratteristica.

Tipi di operazioni con le caratteristiche

GATT supporta quattro tipi di operazioni per interagire con le caratteristiche. Read — il client richiede il valore corrente di una caratteristica al server. Write — il client invia un nuovo valore al server. Notify — il server invia un valore al client senza conferma (più veloce ma meno affidabile). Indicate — il server invia un valore con conferma di ricezione (più affidabile ma più lento). Lo sviluppatore sceglie il tipo in base allo scenario: per le letture del sensore di frequenza cardiaca, Notify è sufficiente; per scrivere la configurazione di una serratura intelligente, è necessario Write con conferma.

kotlin
// Struttura dati GATT nel codice 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 e GAP: differenze tra i profili BLE

La specifica BLE definisce due profili principali: GAP (Generic Access Profile) e GATT (Generic Attribute Profile). GAP è responsabile della scoperta dei dispositivi, dell'instaurazione della connessione e della gestione della visibilità — è il “livello di rete” del BLE. GATT è responsabile dello scambio di dati dopo l'instaurazione della connessione — il “livello applicativo”. Lo sviluppatore usa GAP per scansionare e connettersi a un dispositivo, e GATT per leggere, scrivere e ricevere notifiche dal dispositivo connesso.

CaratteristicaGAPGATT
ScopoScoperta e connessioneScambio dati
RuoliCentrale / PerifericoClient / Server
ProtocolloHCI, Livello CollegamentoATT (Attribute Protocol)
FasePrima della connessioneDopo la connessione
Classe principaleBluetoothAdapterBluetoothGatt

Ruoli in GATT

GATT definisce due ruoli: Server GATT e Client GATT. Il Server è un dispositivo che fornisce dati (ad esempio, un fitness tracker che invia letture della frequenza cardiaca). Il Client è un dispositivo che richiede dati (ad esempio, uno smartphone che legge le letture). Nella maggior parte degli scenari, l'app Android agisce come Client GATT e il periferico BLE agisce come Server GATT. Tuttavia, Android può anche essere un Server GATT — ad esempio, quando un'app emula un dispositivo BLE per altri dispositivi. Il ruolo è determinato nella fase di configurazione della connessione GATT e non cambia durante la sessione.

Come funziona la comunicazione GATT in BLE

Il processo di comunicazione GATT inizia dopo l'instaurazione della connessione BLE tra i dispositivi. Prima, il Client GATT scopre i servizi sul Server GATT attraverso Service Discovery — Android lo fa automaticamente alla connessione tramite BluetoothGatt.discoverServices(). Dopo la scoperta, il client ottiene un elenco di servizi, caratteristiche e descrittori disponibili. Quindi, il client può leggere i valori delle caratteristiche (Read), scrivere nuovi valori (Write) o iscriversi alle notifiche (Set Notify/Indicate). Il Server GATT può inviare Notify/Indicate al client in qualsiasi momento dopo l'instaurazione della connessione.

MTU — Unità Massima di Trasmissione

Per impostazione predefinita, la dimensione di un singolo pacchetto GATT (MTU) in BLE è di 23 byte, di cui 3 byte sono l'intestazione ATT e 20 byte sono dati utili. Se l'applicazione deve trasmettere più dati (ad esempio, aggiornamento firmware OTA), è possibile richiedere un aumento dell'MTU fino a 517 byte tramite requestMtu() in Android. Un MTU maggiore riduce il numero di pacchetti necessari per trasmettere un blocco di dati — invece di 50 pacchetti piccoli, puoi inviarne 2 grandi, riducendo il consumo energetico e accelerando la trasmissione. L'MTU massimo dipende dalla versione BLE e dalle capacità del chip — Bluetooth 5.0 supporta fino a 517 byte, le versioni precedenti fino a 247 byte.

kotlin
// Iscriviti alle notifiche delle caratteristiche
fun enableNotifications(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
    gatt.setCharacteristicNotification(characteristic, true)

    // Abilita CCCD (Descrittore di Configurazione Caratteristica Client)
    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)
    }
}

Gestione delle notifiche

Per ricevere notifiche dal Server GATT su Android, è necessario implementare il callback BluetoothGattCallback.onCharacteristicChanged(). In questo metodo, l'app riceve il valore aggiornato della caratteristica ogni volta che il server invia Notify o Indicate. Per l'elaborazione dei dati in tempo reale, utilizza un buffer e le coroutine Kotlin — questo impedisce il blocco del thread UI durante notifiche intensive (ad esempio, più di 100 letture della frequenza cardiaca al secondo). Per le Indicazioni, devi chiamare gatt.sendResponse() lato server — sul client Android, questo viene gestito automaticamente.

Implementazione di GATT su Android

Su Android, il lavoro con GATT è implementato attraverso le classi del pacchetto android.bluetooth: BluetoothGatt (connessione), BluetoothGattService (servizio), BluetoothGattCharacteristic (caratteristica) e BluetoothGattDescriptor (descrittore). La connessione a un dispositivo BLE inizia chiamando BluetoothDevice.connectGatt() — questo metodo restituisce un BluetoothGatt attraverso il quale vengono eseguite tutte le operazioni successive. Tutti i callback GATT arrivano in BluetoothGattCallback — questa è un'interfaccia asincrona che viene chiamata nello stesso thread in cui è stato creato BluetoothGatt. Importante: tutte le operazioni GATT devono essere eseguite sequenzialmente — chiamare più operazioni contemporaneamente sullo stesso BluetoothGatt causa errori.

Ciclo di vita della connessione GATT

La corretta gestione del ciclo di vita della connessione GATT è fondamentale per la stabilità dell'app BLE. Dopo aver chiamato connectGatt(), l'app attende il callback onConnectionStateChange() con lo stato STATE_CONNECTED. Quindi, il sistema avvia automaticamente Service Discovery, dopo il completamento del quale viene chiamato onServicesDiscovered(). Solo dopo puoi eseguire letture, scritture e iscrizioni. Al termine, chiama sempre gatt.close() in onDestroy() o onPause() — le connessioni GATT non chiuse consumano batteria e possono bloccare la riconnessione allo stesso dispositivo su Android.

kotlin
// Connetti al dispositivo BLE tramite 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) }
    }
}

Profili e servizi GATT standard

Bluetooth SIG definisce decine di profili e servizi GATT standard con UUID a 16 bit fissi. I più comuni: Battery Service (UUID 180F, caratteristica Battery Level 2A19), servizio Heart Rate (UUID 180D, caratteristica Heart Rate Measurement 2A37), servizio Device Information (UUID 180A, caratteristiche Manufacturer Name e Serial Number). L'uso di servizi standard garantisce la compatibilità tra dispositivi di diversi produttori — qualsiasi braccialetto fitness con un servizio Heart Rate dovrebbe funzionare con qualsiasi app Android che lo supporti.

Progettazione di servizi GATT personalizzati

Se i servizi standard non coprono il compito, lo sviluppatore può creare servizi GATT personalizzati con UUID a 128 bit. Nella progettazione di un servizio personalizzato, è necessario: definire un gruppo logico di caratteristiche (ad esempio, “Servizio di Controllo Serratura”), assegnare a ciascuna caratteristica le proprietà corrette (Read, Write, Notify), definire i valori consentiti e le unità di misura tramite il descrittore Characteristic Presentation Format. Per protocolli complessi, si consiglia di includere una caratteristica Command con proprietà Write e una caratteristica Status con Notify — questo segue il pattern Command/Status adottato nelle applicazioni BLE industriali.

kotlin
// Crea servizio GATT personalizzato (Android come Server GATT)
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
}

Domande frequenti

Cos'è GATT in BLE e perché è necessario?

GATT (Generic Attribute Profile) è un profilo Bluetooth Low Energy che definisce la struttura di scambio dati tra dispositivi. È necessario per standardizzare l'accesso alle informazioni: tutti i dispositivi BLE organizzano i dati in servizi e caratteristiche, consentendo a qualsiasi client di leggere i sensori, controllare i dispositivi e ricevere notifiche.

Qual è la differenza tra GATT e GAP?

GAP è responsabile della scoperta e della connessione dei dispositivi BLE (scansione, pubblicità, configurazione connessione). GATT è responsabile dello scambio dati dopo la connessione (lettura, scrittura, notifiche). GAP funziona prima della connessione, GATT dopo. Entrambi i profili sono obbligatori per BLE, ma svolgono funzioni diverse: GAP è il “livello di rete”, GATT è il “livello applicativo”.

Quali servizi e caratteristiche GATT esistono?

I servizi standard includono Battery Service (180F, livello batteria), Heart Rate (180D, polso), Device Information (180A, dati dispositivo). Ogni servizio contiene diverse caratteristiche con UUID a 16 bit. Gli sviluppatori possono creare servizi personalizzati con UUID a 128 bit per attività specifiche — come il controllo di una serratura intelligente o la trasmissione di dati di un fitness tracker.

Come funziona GATT su Android?

Su Android, GATT è implementato tramite BluetoothGatt (connessione), BluetoothGattService (servizio), BluetoothGattCharacteristic (caratteristica) e BluetoothGattDescriptor (descrittore). La connessione avviene tramite connectGatt(), dopodiché gli eventi arrivano tramite BluetoothGattCallback: onConnectionStateChange, onServicesDiscovered, onCharacteristicChanged (per le notifiche). Tutte le operazioni GATT devono essere eseguite sequenzialmente.

Cos'è un UUID in GATT?

UUID (Identificatore Univoco Universale) è un identificatore a 16 o 128 bit che identifica in modo univoco un servizio o una caratteristica in GATT. I servizi standard Bluetooth SIG utilizzano UUID a 16 bit (ad esempio, 180D per Heart Rate). I servizi personalizzati dello sviluppatore utilizzano UUID a 128 bit (ad esempio, 12345678-1234-5678-1234-56789abcdef0). L'UUID consente al client di trovare i dati necessari sul Server GATT.

Riepilogo

  • GATT — un profilo BLE per lo scambio strutturato di dati attraverso una gerarchia di servizi, caratteristiche e descrittori, basato sull'Attribute Protocol (ATT)
  • Gerarchia dati — servizio (gruppo logico), caratteristica (valore specifico con tipo), descrittore (metadati — unità, impostazioni notifica)
  • Ruoli GATT — Server (fornisce dati, solitamente periferico BLE) e Client (legge/scrive, solitamente smartphone Android)
  • Operazioni — Read, Write, Notify (senza conferma, più veloce) e Indicate (con conferma, più affidabile); la scelta dipende dallo scenario
  • API Android — BluetoothGatt, BluetoothGattCallback, BluetoothGattService, BluetoothGattCharacteristic; chiamate asincrone sequenziali tramite callback
  • Profili standard — Battery Service, Heart Rate, Device Information — garantiscono compatibilità tra dispositivi di diversi produttori
  • Servizi personalizzati — UUID a 128 bit per attività uniche; progettati con il pattern Command/Status con proprietà corrette (Read, Write, Notify, Indicate)

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche