蓝牙的基础知识
1. 相关权限申请
权限
android:name="android.permission.BLUETOOTH"/>
android:name="android.permission.BLUETOOTH_ADMIN"/>
注意:android6.0后 需要再添加如下权限定位权限 (如下一个就可以了 也可以多个申请)
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
android:name="android.permission.ACCESS_FINE_LOCATION"/>
2. 搜索蓝牙流程
2.1 打开蓝牙(需要在此之前获取蓝牙适配器BluetoothAdapter 才可以 调起打开蓝牙)
2.1.1 获取蓝牙适配器BluetoothAdapter
BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
2.1.2 权限申请成功后 就可以 打开蓝牙 ,如下是蓝牙是
if(mBluetoothAdapter ==null|| !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent,REQUEST_ENABLE_BT);
}
2.2 扫描蓝牙设备
mBluetoothAdapter.startLeScan(mLeScanCallback)
需要注意:搜索是一个不间断的搜索过程,需要我们手动 停止搜索
所以需要 调用mBluetoothAdapter. mBluetoothAdapter.stopLeScan(mLeScanCallback);
具体代码 定时搜索 如下
private voidscanLeDevice(final booleanenable) {
if(enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(newRunnable() {
@Override
public voidrun() {
mScanning =false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
},SCAN_PERIOD);
mScanning =true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
}else{
mScanning =false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
关于mLeScanCallback的具体实现
privateBluetoothAdapter.LeScanCallback mLeScanCallback =
newBluetoothAdapter.LeScanCallback() {
@Override
public voidonLeScan(finalBluetoothDevice device, intrssi,
byte[] scanRecord) {
//搜索到蓝牙 将会在该方法回调 , device就是搜索到的蓝牙
}
};
注意:蓝牙搜索过程 是没有帮我们过来重复搜索到蓝牙 ,如果想要把搜索结果放在集合返回,有可能一个设备会重复给搜索到,这个时候需要自己做个过滤,可通过bleDevice 的mac 地址不同进行过滤
2. 连接蓝牙流程
2.1 先理清 将会常操作的几个 类的概念 如下是它们的关系流程图
BluetoothGatt:手机与BLE终端设备建立通信的一个管道,只有有了这个管道,之后的所有读写通知操作都是通过这个来操作
BluetoothGattService:蓝牙设备的服务,每个BluetoothGatt有多个BluetoothGattService,在这里我们把BluetoothGattService比喻成班级。而Bluetoothdevice我们把它比喻成学校,一个学校里面可以有很多班级,也就是说我们每台BLE终端设备拥有多个服务,班级(各个服务)之间通过UUID(唯一标识符)区别
BluetoothGattCharacteristic:蓝牙所拥有的特征 。每个BluetoothGattService有多个BluetoothGattCharacteristic。它是手机与BLE终端设备交换数据的关键,我们做的所有事情,目的就是为了得到它。在这里我们把它比喻成学生,一个班级里面有很多个学生,也就是说我们每个服务下拥有多个特征,学生(各个特征)之间通过UUID(唯一标识符)区别。
理清了我们开始连接蓝牙
2.2连接蓝牙
搜索到蓝牙后 拿到蓝牙对象 BluetoothDevice device 调用如下方法
参数:第一个参数是上下文对象,第二个参数是是否自动连接,这里设置为false,第三个参数就是上面的回调方法
mBluetoothGatt = device.connectGatt(this, false,mGattCallback);
mGattCallback的具体实现
privateBluetoothGattCallbackmGattCallback=newBluetoothGattCallback() {
//连接状态改变的回调
@Override
public voidonConnectionStateChange(BluetoothGatt gatt, intstatus,
intnewState) {
if(newState == BluetoothProfile.STATE_CONNECTED) {
// 连接成功后 必须启调用 服务发现 (discoverServices)
//调用后 当回调 onServicesDiscovered(BluetoothGatt gatt, int status)方法
//才属于真正的成功连接
mBluetoothGatt.discoverServices();
}
}
//发现服务的回调
public voidonServicesDiscovered(BluetoothGatt gatt, intstatus) {
if(status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG,"成功发现服务");
}else{
Log.e(TAG,"服务发现失败,错误码为:"+ status);
}
if(status == BluetoothGatt.GATT_SUCCESS) {
if(mBluetoothGatt !=null&& isServiceConnected) {
BluetoothGattService gattService = mBluetoothGatt.getService(UUID_SERVICE);
BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(UUID_NOTIFICATION);
booleanb = mBluetoothGatt.setCharacteristicNotification(characteristic, true);
if(b) {
List descriptors = characteristic.getDescriptors();
for(BluetoothGattDescriptor descriptor : descriptors) {
booleanb1 = descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
if(b1) {
mBluetoothGatt.writeDescriptor(descriptor);
Log.d(TAG,"startRead: "+"监听收数据");
}
}
}
}
}
//写操作的回调
public voidonCharacteristicWrite (BluetoothGatt gatt,BluetoothGattCharacteristic
characteristic,intstatus){
if(status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG,"写入成功"+ characteristic.getValue());
}
}
//读操作的回调
public voidonCharacteristicRead (BluetoothGatt gatt,BluetoothGattCharacteristic
characteristic,intstatus){
if(status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG,"读取成功"+ characteristic.getValue());
}
}
//数据返回的回调(此处接收BLE设备返回数据)
public voidonCharacteristicChanged (BluetoothGatt gatt,BluetoothGattCharacteristic
characteristic){
}
}
}
当 回调 onServicesDiscovered(BluetoothGatt gatt, int status) 方法 后 就可以拿着 gatt(上文有解释概念) 进行 读写通知 操作了
3 关于 读,写,通知,操作
写数据
public void startSend(View view) {
if (mBluetoothGatt != null && isServiceConnected) {
BluetoothGattService gattService = mBluetoothGatt.getService(UUID_SERVICE);
BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(UUID_WRITE);
byte[] bytes = new byte[2];
bytes[0] = 04;
bytes[1] = 01;
characteristic.setValue(bytes);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
mBluetoothGatt.writeCharacteristic(characteristic);
}}
写入成功会回调
public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG, "写入成功" +characteristic.getValue());
}
}
读数据
public void startSend(View view) {
if (mBluetoothGatt != null && isServiceConnected) {
BluetoothGattService gattService = mBluetoothGatt.getService(UUID_SERVICE);
BluetoothGattCharacteristic characteristic = gattService.getCharacteristic(UUID_WRITE);
byte[] bytes = new byte[2];
bytes[0] = 04;
bytes[1] = 01;
characteristic.setValue(bytes);
mBluetoothGatt.readCharacteristic(characteristic);
}
}
读取成功会回调
//读操作的回调
public voidonCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, intstatus) {
if(status == BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG,"读取成功"+characteristic.getValue());
}
}
注意: 在 读写操作过程 不可以 用for 一次性进行操作 会出现阻塞 需要 将读写操作 写入 队列中 一个一个写入 才是比较好的操作 也不会出现堵塞问题
蓝牙的操作流程 就此结束 在此基础上 可以再次封装一层 代码就不出来了,一下是流程图
网友评论