当前位置:首页>安卓APP>安卓开发中的BLE客户端部分

安卓开发中的BLE客户端部分

  • 2026-11-12 11:08:20
安卓开发中的BLE客户端部分

一、BLE 客户端核心作用

客户端 = 扫描 → 连接 → 发现服务 → 读写特征 → 开启通知不需要广播,不需要创建 GattServer!

二、BLE 客户端 标准创建流程

1. 初始化蓝牙

获取BluetoothManager→BluetoothAdapter

2. 开启蓝牙(如未开启)

3. 开启 BLE 扫描

通过BluetoothLeScanner.startScan()扫描周围设备

4. 扫描到目标设备 → 停止扫描

避免耗电

5. 连接设备

device.connectGatt()→ 获取BluetoothGatt

6. 发现服务

连接成功后调用gatt.discoverServices()

7. 获取服务与特征值

根据 UUID 获取Service、Characteristic

8. 读写数据 / 开启通知

读:gatt.readCharacteristic()

写:gatt.writeCharacteristic()

通知:设置特征值的 CCC 描述符

9. 回调处理

所有结果在BluetoothGattCallback中返回

10. 断开连接 & 释放资源

gatt.disconnect()+gatt.close()

三、客户端 vs 服务端 最核心区别

功能
客户端
服务端
广播
不广播
必须广播
Gatt 创建
connectGatt()
openGattServer()
MTU 设置
客户端主动设置
只能接收
发起连接
客户端发起
被动等待
特征操作
主动读写
被动响应

四、 客户端完整代码

1. 权限(和服务端一样)

<uses-permissionandroid:name="android.permission.BLUETOOTH" /><uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN" /><uses-permissionandroid:name="android.permission.BLUETOOTH_SCAN" /><uses-permissionandroid:name="android.permission.BLUETOOTH_CONNECT" /><uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION" /><uses-featureandroid:name="android.hardware.bluetooth_le"android:required="true" />

五、BleClientActivity.kt

import android.annotation.SuppressLintimport android.bluetooth.BluetoothAdapterimport android.bluetooth.BluetoothDeviceimport android.bluetooth.BluetoothGattimport android.bluetooth.BluetoothGattCallbackimport android.bluetooth.BluetoothGattCharacteristicimport android.bluetooth.BluetoothGattDescriptorimport android.bluetooth.BluetoothGattServiceimport android.bluetooth.BluetoothManagerimport android.bluetooth.le.BluetoothLeScannerimport android.bluetooth.le.ScanCallbackimport android.bluetooth.le.ScanResultimport android.content.Contextimport android.os.Bundleimport android.os.Handlerimport android.os.Looperimport android.widget.Toastimport androidx.appcompat.app.AppCompatActivityimport java.util.UUIDclass BleClientActivity : AppCompatActivity() {    // ===================== 必须和服务端一致 =====================    private val SERVICE_UUID = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb")    private val READ_CHAR_UUID = UUID.fromString("0000ffe1-0000-1000-8000-00805f9b34fb")    private val WRITE_CHAR_UUID = UUID.fromString("0000ffe2-0000-1000-8000-00805f9b34fb")    private val CCC_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")    // ===================== 客户端核心对象 =====================    private var bluetoothManager: BluetoothManager? = null    private var bluetoothAdapter: BluetoothAdapter? = null    private var bleScanner: BluetoothLeScanner? = null    private var bluetoothGatt: BluetoothGatt? = null    override funonCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        setContentView(R.layout.activity_ble_client)        initBle()       // 1. 初始化        startScan()     // 2. 开始扫描    }    // ===================== 1. 初始化蓝牙 =====================    private funinitBle() {        bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager        bluetoothAdapter = bluetoothManager?.adapter        bleScanner = bluetoothAdapter?.bluetoothLeScanner        if (bluetoothAdapter?.isEnabled == false) {            bluetoothAdapter?.enable()        }    }    // ===================== 2. 开始扫描 =====================    @SuppressLint("MissingPermission")    private funstartScan() {        showToast("开始扫描BLE设备...")        bleScanner?.startScan(object : ScanCallback() {            override funonScanResult(callbackType: Int, result: ScanResult) {                super.onScanResult(callbackType, result)                val device = result.device                val name = device.name ?: "未知设备"                // 找到目标设备                if (name.contains("你的设备名")) {                    showToast("找到设备:$name")                    bleScanner?.stopScan(this) // 停止扫描                    connectGatt(device)        // 连接设备                }            }        })        // 10秒后停止扫描        Handler(Looper.getMainLooper()).postDelayed({            bleScanner?.stopScan(object : ScanCallback() {})        }, 10000)    }    // ===================== 3. 连接GATT(客户端核心) =====================    @SuppressLint("MissingPermission")    private funconnectGatt(device: BluetoothDevice) {        bluetoothGatt = device.connectGatt(this, false, gattCallback)    }    // ===================== 4. GATT 回调(客户端核心) =====================    private val gattCallback = object : BluetoothGattCallback() {        // 连接状态改变        override funonConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {            super.onConnectionStateChange(gatt, status, newState)            if (newState == BluetoothProfile.STATE_CONNECTED) {                showToast("连接成功,开始发现服务")                gatt?.discoverServices() // 发现服务            }        }        // 发现服务成功        override funonServicesDiscovered(gatt: BluetoothGatt?, status: Int) {            super.onServicesDiscovered(gatt, status)            showToast("发现服务成功")            val service = gatt?.getService(SERVICE_UUID)            val readChar = service?.getCharacteristic(READ_CHAR_UUID)            val writeChar = service?.getCharacteristic(WRITE_CHAR_UUID)            // 读取数据            gatt?.readCharacteristic(readChar)            // 写入数据            writeChar?.value = "Hello BLE Server".toByteArray()            val writeGatt=gatt?.writeCharacteristic(writeChar)            // 开启通知            enableNotification(gatt, writeGatt)        }        // 读取到数据        override funonCharacteristicRead(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) {            super.onCharacteristicRead(gatt, characteristic, status)            val data = characteristic?.value?.toString()            showToast("读取到:$data")        }        // 收到通知        override funonCharacteristicChanged(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?) {            super.onCharacteristicChanged(gatt, characteristic)            val msg = String(characteristic?.value ?: byteArrayOf())            showToast("收到通知:$msg")        }    }    // ===================== 开启通知 =====================    @SuppressLint("MissingPermission")    private funenableNotification(gatt: BluetoothGatt?, char: BluetoothGattCharacteristic?) {        gatt?.setCharacteristicNotification(char, true)        val descriptor = char?.getDescriptor(CCC_DESCRIPTOR_UUID)        descriptor?.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE        gatt?.writeDescriptor(descriptor)    }    // ===================== 释放资源 =====================    @SuppressLint("MissingPermission")    override funonDestroy() {        super.onDestroy()        bluetoothGatt?.disconnect()        bluetoothGatt?.close()    }    private funshowToast(msg: String) {        runOnUiThread { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() }    }}

六、客户端流程 超清晰总结

初始化蓝牙→ 获取适配器

扫描设备→startScan()

找到设备→ 停止扫描

连接 GATT→device.connectGatt()

发现服务→discoverServices()

获取特征→ 根据 UUID 获取

读写 / 通知→ 操作特征值

回调接收数据

断开并释放资源


七、客户端 最重要注意事项

客户端不需要广播

连接使用 device.connectGatt ()

必须在发现服务后才能读写

MTU 由客户端调用 requestMtu () 设置

开启通知必须写CCC 描述符(2902)

读写、发现服务都是异步操作

必须在最后close()释放 Gatt

最新文章

随机文章