对于蓝牙的基础知识我在这里就不赘述了,直接来干货,讲解连接ble蓝牙模块并进行通讯,通讯使用广播模式,结尾附上一个项目的demo。精彩内容即将开始:
一、要使用蓝牙功能,首先要打开权限,在AndroidManifest.xml文件中配置权限信息,如下:
由于蓝牙搜索需要用到位置权限,如果在安装的时候没开通位置权限,蓝牙搜索功能是搜索不到数据的,因此在程序中进去程序在写一个方法来动态提醒用户打开位置权限。
```java
public void local(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//如果 API level 是大于等于 23(Android 6.0) 时
//判断是否具有权限
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
//判断是否需要向用户解释为什么需要申请该权限
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_COARSE_LOCATION)) {
Toast.makeText(MainActivity.this,"需要打开位置权限才可以搜索到Ble设备", Toast.LENGTH_SHORT).show();
}
//请求权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
REQUEST_CODE_ACCESS_COARSE_LOCATION);
}
}
}
二、初始化蓝牙:
/**
* 初始化蓝牙
*/
private void initBle() {
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
Toast.makeText(this, "蓝牙不可用", Toast.LENGTH_LONG).show();
return;
}
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (!mBluetoothAdapter.isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, REQUEST_ENABLE_BT);
return;
}
}
三、搜索蓝牙设备:
```java
/**
* 搜索蓝牙设备
*/
private void scanBleDevice() {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
mBluetoothAdapter.startLeScan(mLeScanCallback);
// 搜索10s
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, 10000);
}
/**
* 搜索蓝牙设备回调
*/
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) {
if (!mBluetoothDeviceList.contains(bluetoothDevice)) {
mBluetoothDeviceList.add(bluetoothDevice);
mRssiList.add(String.valueOf(i));
mDeviceListAdapter.notifyDataSetChanged();
}
}
};
至此,蓝牙的打开搜索的基本功能完成,下面就讲一下蓝牙连接和通讯了。蓝牙的通讯的关键就是UUID,不同的蓝牙模块对应的UUID不用,关于UUID的阐述在此就不多说了自己去问一下度娘。
三、蓝牙连接、通讯单独提出来做为一个服务来用,需要在AndroidManifest.xml文件中注册服务,在aplication加入如下代码:
<service android:name=".BleService" />
BleService的主要功能:蓝牙连接的回调,发送通知,蓝牙的连接,设置蓝牙设备在数据改变时,通知App,发送数据等功能,具体实现如下:
```java
package com.xiao.blecontrol;
import android.app.Service;
import android.bluetooth.*;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import java.util.UUID;
/**
* 蓝牙连接服务
*/
public class BleService extends Service {
private final String TAG = BleService.class.getSimpleName();
private BluetoothGatt mBluetoothGatt;
private BluetoothAdapter mBluetoothAdapter;
// 蓝牙连接状态
private int mConnectionState = 0;
// 蓝牙连接已断开
private final int STATE_DISCONNECTED = 0;
// 蓝牙正在连接
private final int STATE_CONNECTING = 1;
// 蓝牙已连接
private final int STATE_CONNECTED = 2;
// 蓝牙已连接
public final static String ACTION_GATT_CONNECTED = "com.xiao.ble.ACTION_GATT_CONNECTED";
// 蓝牙已断开
public final static String ACTION_GATT_DISCONNECTED = "com.xiao.ble.ACTION_GATT_DISCONNECTED";
// 发现GATT服务
public final static String ACTION_GATT_SERVICES_DISCOVERED = "com.xiao.ble.ACTION_GATT_SERVICES_DISCOVERED";
// 收到蓝牙数据
public final static String ACTION_DATA_AVAILABLE = "com.xiao.ble.ACTION_DATA_AVAILABLE";
// 连接失败
public final static String ACTION_CONNECTING_FAIL = "com.xiao.ble.ACTION_CONNECTING_FAIL";
// 蓝牙数据
public final static String EXTRA_DATA = "com.xiao.ble.EXTRA_DATA";
// 服务标识
//private final UUID SERVICE_UUID = UUID.fromString("0000180a-0000-1000-8000-00805f9b34fb");
public static final UUID SERVICE_UUID = UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb");
//写数据服务
public static final UUID WRITE_SERVICE_UUID = UUID.fromString("0000ffe5-0000-1000-8000-00805f9b34fb");
// 特征标识(读取数据)
private final UUID CHARACTERISTIC_READ_UUID = UUID.fromString("0000ffe4-0000-1000-8000-00805f9b34fb");
// 特征标识(发送数据)
private final UUID CHARACTERISTIC_WRITE_UUID = UUID.fromString("0000ffe9-0000-1000-8000-00805f9b34fb");
// 描述标识
private final UUID DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
// 服务相关
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
public BleService getService() {
return BleService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
release();
return super.onUnbind(intent);
}
/**
* 蓝牙操作回调
* 蓝牙连接状态才会回调
*/
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {//连接转态改变
Log.i(TAG,"监听连接状态改变!");
if (newState == BluetoothProfile.STATE_CONNECTED) {
// 蓝牙已连接
mConnectionState = STATE_CONNECTED;
sendBleBroadcast(ACTION_GATT_CONNECTED);
// 搜索GATT服务
mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
// 蓝牙已断开连接
mConnectionState = STATE_DISCONNECTED;
sendBleBroadcast(ACTION_GATT_DISCONNECTED);
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {//发现服务
// 发现GATT服务
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.w(TAG, "mBluetoothGatt = " + mBluetoothGatt );
sendBleBroadcast(ACTION_GATT_SERVICES_DISCOVERED);
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
// 收到数据
sendBleBroadcast(ACTION_DATA_AVAILABLE, characteristic);
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
sendBleBroadcast(ACTION_DATA_AVAILABLE, characteristic);
}else{
Log.i(TAG,"接收数据失败:"+status);
}
}
};
/**
* 发送通知
*
* @param action 广播Action
*/
private void sendBleBroadcast(String action) {
Intent intent = new Intent(action);
sendBroadcast(intent);
}
/**
* 发送通知
*
* @param action 广播Action
* @param characteristic 数据
*/
private void sendBleBroadcast(String action, BluetoothGattCharacteristic characteristic) {
Log.i(TAG,"我进来了!");
Intent intent = new Intent(action);
if (CHARACTERISTIC_READ_UUID.equals(characteristic.getUuid())) {
intent.putExtra(EXTRA_DATA, characteristic.getValue());
}else{
Log.i(TAG,"走错路了!");
}
sendBroadcast(intent);
}
/**
* 蓝牙连接
*
* @param bluetoothAdapter BluetoothAdapter
* @param address 设备mac地址
* @return true:成功 false:
*/
public boolean connect(BluetoothAdapter bluetoothAdapter, String address) {
if (bluetoothAdapter == null || TextUtils.isEmpty(address)) {
return false;
}
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
if (device == null) {
return false;
}
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
mConnectionState = STATE_CONNECTING;
return true;
}
/**
* 蓝牙断开连接
*/
public void disconnect() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.disconnect();
}
/**
* 释放相关资源
*/
public void release() {
if (mBluetoothGatt == null) {
return;
}
mBluetoothGatt.close();
mBluetoothGatt = null;
}
/**
* 设置蓝牙设备在数据改变时,通知App
*/
public void setBleNotification() {
if (mBluetoothGatt == null) {
sendBleBroadcast(ACTION_CONNECTING_FAIL);
return;
}
// 获取蓝牙设备的服务
BluetoothGattService gattService = mBluetoothGatt.getService(SERVICE_UUID);
if (gattService == null) {
sendBleBroadcast(ACTION_CONNECTING_FAIL);
return;
}
// 获取蓝牙设备的特征
BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(CHARACTERISTIC_READ_UUID);
if (gattCharacteristic == null) {
sendBleBroadcast(ACTION_CONNECTING_FAIL);
return;
}
// 获取蓝牙设备特征的描述符
BluetoothGattDescriptor descriptor = gattCharacteristic.getDescriptor(DESCRIPTOR_UUID);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
if (mBluetoothGatt.writeDescriptor(descriptor)) {
// 蓝牙设备在数据改变时,通知App,App在收到数据后回调onCharacteristicChanged方法
mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);
}
}
/**
* 发送数据
*
* @param data 数据
* @return true:发送成功 false:发送失败
*/
public boolean sendData(byte[] data) {
// 获取蓝牙设备的服务
BluetoothGattService gattService = null;
if (mBluetoothGatt != null) {
gattService = mBluetoothGatt.getService(WRITE_SERVICE_UUID);
}
if (gattService == null) {
return false;
}
// 获取蓝牙设备的特征
BluetoothGattCharacteristic gattCharacteristic = gattService.getCharacteristic(CHARACTERISTIC_WRITE_UUID);
if (gattCharacteristic == null) {
return false;
}
// 发送数据
gattCharacteristic.setValue(data);
return mBluetoothGatt.writeCharacteristic(gattCharacteristic);
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.readCharacteristic(characteristic);
}
}
在主活动注册蓝牙接收器
/**
* 注册蓝牙信息接收器
*/
private void registerBleReceiver() {
// 绑定服务
Intent intent = new Intent(this, BleService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
startService(intent);
// 注册蓝牙信息广播接收器
IntentFilter filter = new IntentFilter();
filter.addAction(BleService.ACTION_GATT_CONNECTED);
filter.addAction(BleService.ACTION_GATT_DISCONNECTED);
filter.addAction(BleService.ACTION_GATT_SERVICES_DISCOVERED);
filter.addAction(BleService.ACTION_DATA_AVAILABLE);
filter.addAction(BleService.ACTION_CONNECTING_FAIL);
mBleReceiver = new BleReceiver();
registerReceiver(mBleReceiver, filter);
}
至此蓝牙的连接,通讯功能基本完成。下面提供一个完整的demo,只需要修改相关服务的UUID就能运行。代码地址:https://gitee.com/longsis/BleControl.git