BluetoothGatt — nó là gì, phương thức và giao thức GATT BLE trong Android

Tác giả: IT Sectr Đã đăng: 2026-07-16 Thời gian đọc: 10 phút

BluetoothGatt — một lớp Android cung cấp API cho hoạt động của GATT client (Generic Attribute Profile) qua kết nối BLE. BluetoothGatt đóng gói kết nối đến máy chủ GATT từ xa (thiết bị BLE ngoại vi) và quản lý tất cả hoạt động của hồ sơ: khám phá dịch vụ, đọc và ghi đặc tính, đăng ký nhận thông báo và chỉ định. Một phiên bản BluetoothGatt được lấy qua BluetoothDevice.connectGatt() với BluetoothGattCallback. Theo Android Developers, 2026, BluetoothGatt là lớp trung tâm cho giao tiếp BLE hai chiều, hỗ trợ các hoạt động GATT từ BLE 4.0 đến BLE 5.4.

Những điểm chính

  • BluetoothGatt — lớp Android cho GATT client quản lý kết nối BLE với thiết bị ngoại vi
  • connectGatt() — phương thức BluetoothDevice để tạo BluetoothGatt; chấp nhận context, autoConnect, callback và transport
  • discoverServices() — phương thức để lấy hệ thống phân cấp GATT: dịch vụ (BluetoothGattService), đặc tính (BluetoothGattCharacteristic)
  • readCharacteristic/writeCharacteristic — phương thức đọc và ghi với kết quả bất đồng bộ qua BluetoothGattCallback
  • setCharacteristicNotification — phương thức đăng ký nhận thông báo BLE với ghi bộ mô tả CCCD bắt buộc

BluetoothGatt là gì: bản chất và tạo kết nối

BluetoothGatt — một đối tượng proxy đại diện cho kết nối GATT giữa thiết bị Android (trung tâm) và thiết bị ngoại vi BLE (máy chủ). Mỗi phiên bản BluetoothGatt tương ứng với một kết nối BLE đang hoạt động. Tất cả hoạt động của hồ sơ GATT được thực hiện qua nó: khám phá, đọc, ghi, thông báo. BluetoothGatt không được tạo trực tiếp — nó được trả về bởi phương thức BluetoothDevice.connectGatt().

Tạo BluetoothGatt yêu cầu bốn tham số. Context — ngữ cảnh ứng dụng (Activity hoặc Application). autoConnect — nếu false, Android ngay lập tức khởi tạo kết nối trực tiếp; nếu true, Android tự động kết nối khi phát hiện thiết bị (hữu ích cho kết nối nền). BluetoothGattCallback — callback bắt buộc cho tất cả sự kiện GATT. transport — BluetoothDevice.TRANSPORT_LE (BLE) hoặc TRANSPORT_BREDR (Classic). Trên thiết bị BLE, luôn sử dụng TRANSPORT_LE.

Vòng đời BluetoothGatt bao gồm năm trạng thái. DISCONNECTED — trạng thái ban đầu. CONNECTING — sau khi gọi connectGatt, trước khi xác nhận. CONNECTED — sau onConnectionStateChange với STATE_CONNECTED. Sau kết nối, discoverServices() được gọi để lấy hệ thống phân cấp GATT. Sau khi hoàn thành công việc — disconnect() và close() để giải phóng tài nguyên hệ thống. Không gọi close(), ứng dụng có thể cạn kiệt giới hạn kết nối BLE của Android (thường 4–8).

kotlin
// Đang tạo kết nối BluetoothGatt
import android.bluetooth.*

class GattConnector(private val context: Context) {

    private var bluetoothGatt: BluetoothGatt? = null

    fun connect(device: BluetoothDevice): BluetoothGatt? {
        // Đóng kết nối trước đó nếu có
        close()

        bluetoothGatt = device.connectGatt(
            context,
            false,  // autoConnect = false ( )
            object : BluetoothGattCallback() {
                override fun onConnectionStateChange(
                    gatt: BluetoothGatt, status: Int, newState: Int
                ) {
                    when (newState) {
                        BluetoothProfile.STATE_CONNECTED -> {
                            // 2. Kết nối đã thiết lập → Khám phá
                            gatt.discoverServices()
                        }
                        BluetoothProfile.STATE_DISCONNECTED -> {
                            // 3. Mất kết nối
                            close()
                        }
                    }
                }

                override fun onServicesDiscovered(
                    gatt: BluetoothGatt, status: Int
                ) {
                    if (status == BluetoothGatt.GATT_SUCCESS) {
                        // 4. Đã nhận hệ thống phân cấp GATT
                        onGattReady(gatt)
                    }
                }
            },
            BluetoothDevice.TRANSPORT_LE
        )
        return bluetoothGatt
    }

    private fun onGattReady(gatt: BluetoothGatt) {
        // GATT sẵn sàng cho hoạt động đọc/ghi
    }

    fun close() {
        bluetoothGatt?.disconnect()
        bluetoothGatt?.close()
        bluetoothGatt = null
    }
}

Lớp GattConnector minh họa cách tạo BluetoothGatt đúng cách. Tham số autoConnect=false có nghĩa là kết nối trực tiếp (cho thiết bị được quét). Khi onConnectionStateChange với STATE_CONNECTED, discoverServices() được gọi ngay lập tức. onServicesDiscovered báo hiệu GATT đã sẵn sàng. close() gọi tuần tự disconnect() và close() — không có close() tài nguyên hệ thống không được giải phóng, dẫn đến rò rỉ kết nối BLE.

Khám phá dịch vụ và đặc tính qua BluetoothGatt

discoverServices() — phương thức GATT đầu tiên được gọi sau kết nối. Nó bắt đầu tìm kiếm bất đồng bộ tất cả dịch vụ trên thiết bị ngoại vi BLE. Kết quả đến trong onServicesDiscovered() với mã trạng thái: GATT_SUCCESS (0) — thành công, 133 — GATT_ERROR, 8 — GATT_CONNECTION_TIMEOUT. Sau khi khám phá thành công, BluetoothGatt điền danh sách dịch vụ có sẵn qua getServices().

Mỗi BluetoothGattService chứa danh sách BluetoothGattCharacteristic. Một đặc tính có UUID, thuộc tính (PROPERTY_READ, PROPERTY_WRITE, PROPERTY_NOTIFY) và bộ mô tả tùy chọn. Các thuộc tính xác định hoạt động nào được phép: nếu đặc tính không có PROPERTY_READ, gọi readCharacteristic sẽ trả về lỗi. Sử dụng getDescriptors() để lấy bộ mô tả đặc tính.

kotlin
// Khám phá dịch vụ và tìm kiếm đặc tính
class GattServiceExplorer {

    // Tìm dịch vụ theo UUID
    fun findService(gatt: BluetoothGatt, uuid: UUID): BluetoothGattService? {
        return gatt.services?.firstOrNull { it.uuid == uuid }
    }

    // Tìm đặc tính trong dịch vụ
    fun findCharacteristic(
        service: BluetoothGattService,
        uuid: UUID
    ): BluetoothGattCharacteristic? {
        return service.characteristics?.firstOrNull { it.uuid == uuid }
    }

    // Lấy tất cả hoạt động đặc tính được hỗ trợ
    fun getCharacteristicProperties(chars: BluetoothGattCharacteristic): List<String> {
        val props = mutableListOf<String>()
        with(chars.properties) {
            if (and(BluetoothGattCharacteristic.PROPERTY_READ) != 0) props.add("READ")
            if (and(BluetoothGattCharacteristic.PROPERTY_WRITE) != 0) props.add("GHI")
            if (and(BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) != 0) props.add("GHI_KHÔNG_PHẢN_HỒI")
            if (and(BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) props.add("NOTIFY")
            if (and(BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) props.add("INDICATE")
        }
        return props
    }

    // Ghi nhật ký toàn bộ hệ thống phân cấp GATT
    fun dumpGattTree(gatt: BluetoothGatt) {
        gatt.services?.forEach { service ->
            print("Service: ${service.uuid}")
            service.characteristics?.forEach { char ->
                print("  Characteristic: ${char.uuid}, properties: ${char.properties}")
                char.descriptors?.forEach { desc ->
                    print("    Descriptor: ${desc.uuid}")
                }
            }
        }
    }
}

Lớp GattServiceExplorer cung cấp tiện ích để điều hướng hệ thống phân cấp GATT. findService và findCharacteristic tìm kiếm dịch vụ và đặc tính theo UUID. getCharacteristicProperties kiểm tra mặt nạ bit của thuộc tính qua and(). dumpGattTree in toàn bộ hệ thống phân cấp vào nhật ký — hữu ích khi gỡ lỗi thiết bị BLE. Tất cả hoạt động trên BluetoothGatt phải được thực hiện sau onServicesDiscovered thành công, nếu không getServices() sẽ trả về danh sách rỗng.

Đọc đặc tính BLE: readCharacteristic và readDescriptor

readCharacteristic() — phương thức bất đồng bộ BluetoothGatt để đọc giá trị đặc tính từ thiết bị BLE từ xa. Kết quả đến trong onCharacteristicRead() của BluetoothGattCallback. Nếu thiết bị có 2+ đặc tính khớp (không phổ biến nhưng có thể), readCharacteristic() có thể đọc không đúng mục tiêu — an toàn hơn khi gọi readCharacteristic() trên phiên bản BluetoothGattCharacteristic thay vì theo UUID.

readDescriptor() — phương thức để đọc giá trị bộ mô tả đặc tính. Một bộ mô tả điển hình là CCCD (Client Characteristic Configuration Descriptor, UUID 0x2902), xác định thông báo có được bật hay không. Kết quả trong onDescriptorRead(). Đọc bộ mô tả hiếm khi cần thiết trong thực tế — CCCD được quản lý bởi setCharacteristicNotification(), nhưng cho bộ mô tả tùy chỉnh (User Description 0x2901, Presentation Format 0x2904) readDescriptor() là cách duy nhất để lấy siêu dữ liệu.

MTU và đọc dữ liệu lớn — nếu giá trị đặc tính vượt quá MTU (23 byte cho BLE 4.0), Android tự động phân mảnh và tập hợp lại dữ liệu qua một chuỗi yêu cầu đọc thông qua ngăn xếp BLE. Đối với BLE 5.0+ với MTU mở rộng (lên đến 251 byte), không cần phân mảnh — một lần đọc trả về dữ liệu hoàn chỉnh. Trước khi đọc, bạn có thể gọi requestMtu() để thương lượng MTU tối đa.

kotlin
// Đọc đặc tính và bộ mô tả qua BluetoothGatt
class GattReader {

    fun readHeartRate(gatt: BluetoothGatt) {
        // UUID dịch vụ nhịp tim = 0x180D
        val service = gatt.getService(UUID.fromString("0000180D-0000-1000-8000-00805F9B34FB"))
            ?: return
        // UUID đo nhịp tim = 0x2A37
        val characteristic = service.getCharacteristic(
            UUID.fromString("00002A37-0000-1000-8000-00805F9B34FB")
        ) ?: return

        if (hasProperty(characteristic, BluetoothGattCharacteristic.PROPERTY_READ)) {
            gatt.readCharacteristic(characteristic)
        }
    }

    fun readDescriptor(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
        // CCCD (0x2902)
        val cccd = characteristic.getDescriptor(
            UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
        )
        cccd?.let { gatt.readDescriptor(it) }
    }

    // Xử lý dữ liệu trong callback onCharacteristicRead:
    fun parseHeartRate(value: ByteArray): Int {
        // Nhịp tim BLE: bytes = flags, second = bpm
        return if (value.isNotEmpty()) value[1].toInt() and 0xFF else 0
    }

    private fun hasProperty(char: BluetoothGattCharacteristic, prop: Int): Boolean {
        return char.properties and prop != 0
    }
}

Lớp GattReader minh họa đọc đặc tính nhịp tim. Dịch vụ 0x180D chứa đặc tính 0x2A37 (Heart Rate Measurement) — hồ sơ BLE tiêu chuẩn của Bluetooth SIG. Trước khi đọc, thuộc tính PROPERTY_READ được kiểm tra qua hasProperty. parseHeartRate phân tích định dạng BLE nhịp tim: byte đầu tiên — flags (định dạng dữ liệu), thứ hai — giá trị bpm. Bộ mô tả CCCD (0x2902) được đọc để kiểm tra trạng thái thông báo.

Ghi đặc tính: writeCharacteristic với WriteType

writeCharacteristic() — phương thức BluetoothGatt để ghi dữ liệu lên thiết bị ngoại vi BLE. Trên Android API 33+, writeCharacteristic() đã được thay thế bằng writeCharacteristic(request), trong đó BluetoothGattCharacteristicWriteRequest là đối tượng yêu cầu chứa đặc tính, mảng byte và WriteType. Phương thức cũ writeCharacteristic(characteristic) với setValue() không được khuyến khích. WriteType xác định hành vi yêu cầu: WRITE_TYPE_DEFAULT (phụ thuộc vào thuộc tính đặc tính), WRITE_TYPE_NO_RESPONSE (không phản hồi) và WRITE_TYPE_SIGNED (ủy quyền).

Chọn WriteType ảnh hưởng đến tốc độ và độ tin cậy. WRITE_TYPE_DEFAULT thường tương ứng với withResponse (nếu đặc tính có PROPERTY_WRITE) hoặc withoutResponse (nếu có PROPERTY_WRITE_NO_RESPONSE). Đối với dữ liệu truyền phát (cập nhật OTA, nhật ký), sử dụng WRITE_TYPE_NO_RESPONSE — thông lượng tối đa. Đối với lệnh có đảm bảo gửi (bật, cấu hình) — WRITE_TYPE_DEFAULT với xác nhận qua onCharacteristicWrite.

kotlin
// Ghi đặc tính BLE trên Android API 33+
class GattWriter {

    // Ghi với phản hồi (withResponse)
    fun writeWithResponse(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, data: ByteArray) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            // API 33+: writeCharacteristic
            val request = BluetoothGattCharacteristicWriteRequest(
                characteristic,
                data,
                BluetoothGattCharacteristicWriteRequest.WRITE_TYPE_DEFAULT,
                @android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
            )
            gatt.writeCharacteristic(request)
        } else {
            // API < 33:   (deprecated)
            characteristic.setValue(data)
            gatt.writeCharacteristic(characteristic)
        }
    }

    // Ghi không phản hồi (tốc độ tối đa)
    fun writeWithoutResponse(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, data: ByteArray) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            val request = BluetoothGattCharacteristicWriteRequest(
                characteristic,
                data,
                BluetoothGattCharacteristicWriteRequest.WRITE_TYPE_NO_RESPONSE,
                @android.annotation.RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
            )
            gatt.writeCharacteristic(request)
        } else {
            characteristic.setValue(data)
            characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
            gatt.writeCharacteristic(characteristic)
        }
    }

    // Callback onCharacteristicWrite (API 33+)
    private val writeCallback = object : BluetoothGattCallback() {
        override fun onCharacteristicWrite(
            gatt: BluetoothGatt,
            characteristic: BluetoothGattCharacteristic,
            value: ByteArray,
            status: Int,
            callbackType: Int
        ) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                print("Write success: ${value.size} bytes")
            }
        }
    }
}

Lớp GattWriter hỗ trợ cả hai WriteType cho các cấp API khác nhau. writeWithResponse sử dụng WRITE_TYPE_DEFAULT — thiết bị BLE xác nhận ghi qua onCharacteristicWrite. writeWithoutResponse sử dụng WRITE_TYPE_NO_RESPONSE — dữ liệu được gửi không cần xác nhận, thông lượng tối đa. Trên API 33+, sử dụng writeCharacteristic(request) mới với BluetoothGattCharacteristicWriteRequest. Trên API < 33 — setValue() cũ + writeCharacteristic().

Đăng ký nhận thông báo: setCharacteristicNotification và CCCD

setCharacteristicNotification() — phương thức BluetoothGatt để đăng ký nhận thông báo về thay đổi đặc tính trên thiết bị ngoại vi. Sau khi kích hoạt đăng ký, thiết bị BLE gửi giá trị mới qua onCharacteristicChanged(). Tuy nhiên, setCharacteristicNotification() chỉ kích hoạt thông báo cục bộ Android — để bật thông báo trên chính thiết bị BLE, bạn cũng phải ghi giá trị 0x0100 vào bộ mô tả CCCD (0x2902).

CCCD (Client Characteristic Configuration Descriptor) — bộ mô tả kiểm soát việc gửi thông báo từ thiết bị ngoại vi BLE. Giá trị 0x0000 — thông báo tắt, 0x0100 — thông báo bật, 0x0200 — chỉ định bật. Ghi vào CCCD được thực hiện qua writeDescriptor() trên BluetoothGatt sau khi gọi setCharacteristicNotification(). Android không tự động ghi CCCD — trách nhiệm này thuộc về nhà phát triển.

kotlin
// Đăng ký thông báo BLE chính xác
class GattNotificationManager {

    // 1. Bật thông báo
    fun enableNotification(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
        // Bước 1: đăng ký cục bộ Android
        val success = gatt.setCharacteristicNotification(characteristic, true)
        if (!success) {
            print("Đăng ký thất bại")
            return
        }

        // Bước 2: ghi CCCD (0x2902) trên thiết bị BLE
        val cccdDescriptor = characteristic.getDescriptor(
            UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
        ) ?: return

        // 0x0100 = thông báo, 0x0200 = chỉ định
        val cccdValue = if (characteristic.properties
            and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0) {
            BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE  // [0x01, 0x00]
        } else {
            BluetoothGattDescriptor.ENABLE_INDICATION_VALUE     // [0x02, 0x00]
        }

        cccdDescriptor.setValue(cccdValue)
        gatt.writeDescriptor(cccdDescriptor)
    }

    // 2. Khám phá đặc tính
    fun disableNotification(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
        gatt.setCharacteristicNotification(characteristic, false)
        val cccdDescriptor = characteristic.getDescriptor(
            UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
        ) ?: return
        cccdDescriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE)
        gatt.writeDescriptor(cccdDescriptor)
    }

    // 3. Callback thông báo
    private val notificationCallback = object : BluetoothGattCallback() {
        override fun onCharacteristicChanged(
            gatt: BluetoothGatt,
            characteristic: BluetoothGattCharacteristic,
            value: ByteArray,
            callbackType: Int
        ) {
            // Giá trị mới từ thiết bị ngoại vi BLE
            print("Notification: ${value.size} bytes")
        }
    }
}

Lớp GattNotificationManager thực hiện giao thức đăng ký thông báo BLE hai bước chính xác. enableNotification đầu tiên gọi setCharacteristicNotification(true) trên Android, sau đó ghi 0x0100 vào bộ mô tả CCCD qua writeDescriptor. disableNotification thực hiện các hoạt động ngược lại. Không ghi CCCD, thiết bị BLE sẽ không gửi thông báo — đây là lỗi phổ biến nhất của nhà phát triển BLE trên Android.

Ví dụ GATT client trong Kotlin với BluetoothGattCallback

Ví dụ hoàn chỉnh về GATT client trong Kotlin kết hợp tạo BluetoothGatt, khám phá, đọc và đăng ký thông báo trong một trình quản lý duy nhất sử dụng coroutine cho xử lý bất đồng bộ.

kotlin
// GATT client hoàn chỉnh với coroutine trong Kotlin
class GattClient(context: Context) {

    private val context = context.applicationContext
    private var gatt: BluetoothGatt? = null

    // Kết nối với coroutine
    suspend fun connect(device: BluetoothDevice): Boolean =
        suspendCoroutine { continuation ->
            gatt = device.connectGatt(
                context, false,
                object : BluetoothGattCallback() {
                    override fun onConnectionStateChange(
                        gatt: BluetoothGatt, status: Int, newState: Int
                    ) {
                        if (newState == BluetoothProfile.STATE_CONNECTED) {
                            gatt.discoverServices()
                        } else {
                            continuation.resume(false)
                        }
                    }

                    override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
                        continuation.resume(status == BluetoothGatt.GATT_SUCCESS)
                    }
                },
                BluetoothDevice.TRANSPORT_LE
            )
        }

    // Đọc đặc tính qua coroutine
    suspend fun readCharacteristicValue(char: BluetoothGattCharacteristic): ByteArray? =
        suspendCoroutine { continuation ->
            gatt?.let { gatt ->
                // Lưu thẻ đặc tính để nhận dạng callback
                gatt.setCharacteristic(char, null)  // cho API < 33
                gatt.readCharacteristic(char)
            }
        }

    // Đóng kết nối
    fun release() {
        gatt?.disconnect()
        gatt?.close()
        gatt = null
    }
}

GATT client GattClient sử dụng coroutine (suspendCoroutine) để chuyển đổi API BluetoothGatt dựa trên callback thành các cuộc gọi tuần tự. connect() chờ onServicesDiscovered, sau đó hệ thống phân cấp GATT có sẵn. readCharacteristicValue() chờ onCharacteristicRead. Cách tiếp cận này loại bỏ lồng callback và làm cho mã BLE tuyến tính. release() đảm bảo dọn dẹp tài nguyên — cuộc gọi bắt buộc trong onDestroy của Activity hoặc ViewModel.onCleared.

Câu hỏi thường gặp

BluetoothGatt trong Android là gì?

BluetoothGatt — lớp Android cho GATT client quản lý kết nối BLE với thiết bị ngoại vi. Nó được tạo qua BluetoothDevice.connectGatt(), cung cấp các phương thức discoverServices(), readCharacteristic(), writeCharacteristic(), setCharacteristicNotification(). Kết quả của tất cả hoạt động đến bất đồng bộ qua BluetoothGattCallback. Không có BluetoothGatt, giao tiếp BLE hai chiều trên Android là không thể.

Tại sao onServicesDiscovered trả về trạng thái 133?

Trạng thái 133 (GATT_ERROR) cho thấy lỗi nội bộ của ngăn xếp BLE Android. Nguyên nhân: thiết bị ngắt kết nối trong quá trình khám phá, MTU dưới mức tối thiểu (23 byte) hoặc ngăn xếp BLE bị quá tải. Giải pháp: thử lại discoverServices() với độ trễ 500ms, kiểm tra RSSI thiết bị và đảm bảo thiết bị ngoại vi hỗ trợ khám phá GATT ở trạng thái hiện tại.

Làm thế nào để ghi đặc tính với xác nhận đúng cách?

Để ghi với xác nhận, gọi writeCharacteristic() với WRITE_TYPE_DEFAULT (API 33+: BluetoothGattCharacteristicWriteRequest). Khi thành công, thiết bị BLE gửi xác nhận và Android gọi onCharacteristicWrite với GATT_SUCCESS. Nếu thiết bị không phản hồi trong vòng 30 giây (thời gian chờ ngăn xếp), callback trả về trạng thái lỗi. Cho watchdog, sử dụng Handler với postDelayed.

Làm thế nào để làm việc với BLE trên Android 33+?

Trên Android 13+ (API 33), các phương thức BluetoothGatt đã thay đổi: writeCharacteristic() hiện chấp nhận BluetoothGattCharacteristicWriteRequest, readCharacteristic() — BluetoothGattCharacteristicReadRequest. Các phương thức cũ setValue()/writeCharacteristic() không được khuyến khích. BluetoothGattCallback cũng thay đổi: onCharacteristicRead(), onCharacteristicWrite(), onCharacteristicChanged() nhận ByteArray value và callbackType. Sử dụng Build.VERSION.SDK_INT để phân nhánh.

Android hỗ trợ bao nhiêu kết nối BLE?

Android hỗ trợ 4–8 kết nối BLE GATT đồng thời (tùy thuộc vào nhà sản xuất và phiên bản Android). Pixel/Google: lên đến 7, Samsung: lên đến 5, Xiaomi: lên đến 4. Khi vượt quá giới hạn, connectGatt trả về null hoặc onConnectionStateChange với lỗi. Để làm việc với số lượng lớn thiết bị, sử dụng kết nối tuần hoàn hoặc Bluetooth Mesh.

Tổng kết

  • BluetoothGatt — GATT client Android cho kết nối BLE, được tạo qua BluetoothDevice.connectGatt() với BluetoothGattCallback
  • discoverServices() — bước bắt buộc sau kết nối để lấy dịch vụ, đặc tính và bộ mô tả của thiết bị BLE
  • Đọc — readCharacteristic() với kết quả bất đồng bộ trong onCharacteristicRead(); cho dữ liệu lớn cần thương lượng MTU
  • Ghi — writeCharacteristic() với WriteType: DEFAULT (withResponse) hoặc NO_RESPONSE (không xác nhận)
  • Thông báo — kích hoạt hai bước: setCharacteristicNotification() + ghi CCCD (0x2902) với giá trị 0x0100
  • API 33+ — phương thức mới writeCharacteristic(request) và readCharacteristic(request) với đối tượng yêu cầu
  • Giải phóng tài nguyên — gọi bắt buộc disconnect() và close() để ngăn rò rỉ kết nối BLE

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm