蓝牙
蓝牙通讯分为:经典蓝牙与低功耗蓝牙
现在所说的蓝牙设备,大部分都是在说4.0设备,ble也特指4.0设备。 在4.0之前重要的版本有2.1版本-基本速率/增强数据率(BR/EDR)和3.0 高速蓝牙版本,这些统称为经典蓝牙。
1.1 经典蓝牙
核心API:
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
总结:
通过Android 系统提供API,进行蓝牙连接的前期工作准备(蓝牙开启,权限添加),外界设备扫描,设备连接(获取通讯BluetoothSocket),数据收发(IO流),资源释放 等等,完成Android系统与硬件设备通过蓝牙模式的数据收发功能。
1.1.1 权限检测:想要使用蓝牙必须给予应用相应的蓝牙权限
//需要此权限来执行任何蓝牙通信,如请求一个连接、接受一个连接和传输数据。
<uses-permission android:name="android.permission.BLUETOOTH"/>
//如果你想让你的应用启动设备发现或操纵蓝牙设置,必须申报bluetooth_admin许可
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
1.1.2 检测蓝牙是否开启:若没有开启,则跳转系统蓝牙功能相关选择开启蓝牙
// If BT is not on, request that it be enabled.
// setupChat() will then be called during onActivityResult
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
// Otherwise, setup the chat session
} else if (mChatService == null) {
setupChat();
}
1.1.3 设备扫描
/**
* Start device discover with the BluetoothAdapter
*/
private void doDiscovery() {
// If we're already discovering, stop it
if (mBtAdapter.isDiscovering()) {
mBtAdapter.cancelDiscovery();
}
// Request discover from BluetoothAdapter
mBtAdapter.startDiscovery();
}
蓝牙设备搜索的结果,Android系统会有对应的广播,我们可以在广播中对它进行接收并且进行相应的处理:
// Register for broadcasts when a device is discovered
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
// Register for broadcasts when discovery has finished
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
/**
* Create by dgs
* Description 处理蓝牙状态
**/
public class BluetoothStatuHandler implements IStatuHandler {
public static final String ACTION_BT_CONNECTED = "BT_CONNECTED";
public static final String ACTION_BT_DISCONNECTED = "BT_DISCONNECTED";
@Override
public void registAction(IntentFilter intentFilter) {
//=======================bluetooth========================= start
intentFilter.addAction(ACTION_BT_DISCONNECTED);
intentFilter.addAction(ACTION_BT_CONNECTED);
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
intentFilter.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
//=======================bluetooth========================= end
}
@Override
public boolean onStatuChanged(String action, Context context, Intent intent) {
if (ACTION_BT_CONNECTED.equals(action)) {
Log.d("mBleCallback","蓝牙连接");
onBluetoothConnected(intent);
} else if (ACTION_BT_DISCONNECTED.equals(action)) {
Log.d("mBleCallback","蓝牙断开了BT");
onBluetoothDisconnected(intent);
} else if (BluetoothDevice.ACTION_FOUND.equals(action)) {
Log.d("mBleCallback","蓝牙查找");
onBluetoothFound(intent);
} else if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) {
Log.d("mBleCallback","蓝牙断开了-------");
onACLBluetoothDisconnected(intent);
} else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){
if (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_OFF) {
Log.d("mBleCallback","蓝牙断开了*******");
onACLBluetoothDisconnected(intent);
}
} else {
return false;
}
return true;
}
/**
* 蓝牙连接上
* @param intent
*/
private void onBluetoothConnected(Intent intent) {
ConnectedBluetoothEvent event = new ConnectedBluetoothEvent();
event.setConnected(true);
EventBusManager.postEvent(event);
EventBus.getDefault().post(CollectionDevice.BLUETOOTH_CONNECTED);
}
/**
* 蓝牙断开链接(来自自定义广播)
* @param intent
*/
private void onBluetoothDisconnected(Intent intent) {
ConnectedBluetoothEvent event = new ConnectedBluetoothEvent();
event.setConnected(false);
EventBusManager.postEvent(event);
// String msg = "蓝牙连接已断开,请退出目前的诊断系统,再重新进入需要诊断的电控系统,否则可能导致测试数据不准确或无法测试... ";
EventBus.getDefault().post(CollectionDevice.BLUETOOTH_DISCONNECTED);
}
/**
* 发现新蓝牙
* @param intent
*/
private void onBluetoothFound(Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
FoundBluetoothEvent foundBluetoothEvent = new FoundBluetoothEvent();
Loger.printLog("MTFConnManager ", " 发现蓝牙设备 onBluetoothFound " + device.getAddress());
foundBluetoothEvent.setBluetoothDevice(device);
EventBusManager.postEvent(foundBluetoothEvent);
//
// // 蓝牙已连上,不需再执行连接操作
// if (ConnectManagement.IsBluetooth) {
// return;
// }
//
Message msg = new Message();
msg.what = 1;
msg.obj = device;
ConnectManagement.mBTHandler.handleMessage(msg);
//
// L.e("蓝牙已匹配搜索:"+device.toString()+",我的:"+ConnectManagement.bluetoothAddress);
ConnectManagement.bluetoothAddress="00:06:66:E5:3A:11";
// if (device.toString().equalsIgnoreCase(ConnectManagement.bluetoothAddress)) {
// L.e("蓝牙已匹配");
// if (ConnectManagement.CheckDriver == false) {
// new Thread(new Runnable() {
// @Override
// public void run() {
// ConnectManagement.myConnect(device);
// }
// }).start();
// L.i("广播处理函数:", "成功查找到设备!");
// }
// }
}
/**
* 蓝牙断开链接(来自系统广播)
* @param intent
*/
private void onACLBluetoothDisconnected(Intent intent) {
ConnectedBluetoothEvent event = new ConnectedBluetoothEvent();
EventBusManager.postEvent(event);
EventBus.getDefault().post( CollectionDevice.BLUETOOTH_DISCONNECTED);
//
// // 可能出现在退出app立马重启,蓝牙自动连接时
// if (ConnectManagement.isDiscovering(ConnectManagement.EnvEnum.BLUETOOTH_CLASSICAL)) {
// return;
// }
//
// String msg = "蓝牙连接已断开 ";
// disconnect(msg);
// EventBus.getDefault().post(Constants.BLUETOOTH_DISCONNECTED);
}
}
1.1.4 设备连接
根据广播中接受蓝牙设备对信息,并设置UUID后,执行连接方法
private void connectToDevice(BluetoothDevice device) {
UUID uuid = deviceInfo.getUuid()/*UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")*/;
try {
btSocket = device.createRfcommSocketToServiceRecord(uuid);
if (isConnecting()) {
scoketConnected();
}
return;
} catch (Exception e) {
e.printStackTrace();
closeSocketConnect();
try {
btSocket = (BluetoothSocket) device.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(device, 1);
if (isConnecting()) {
scoketConnected();
}
} catch (Exception e1) {
closeSocketConnect();
}
}
}
连接成功之后会获取到Socket对象,进而生成数据收发的数据流对象
private void scoketConnected() throws Exception {
btSocket.connect();
mInputStream = btSocket.getInputStream();
mOutputStream = btSocket.getOutputStream();
connected();
}
1.1.5 数据收发
发送数据
@Override
public boolean sendData(byte[] data) {
boolean statu = false;
if (mOutputStream != null) {
try {
mOutputStream.write(data);
mOutputStream.flush();
statu = true;
onDataSended(data);
} catch (Exception ex) {
onSendDataError(ErrorCode.BLUETOOTH_WRITE_EXCEPTION, "数据写入时异常");
}
} else {
onSendDataError(ErrorCode.BLUETOOTH_WRITE_CLOSED, "数据写入时数据流已经关闭,建议从新链接");
}
return statu;
}
接收数据
数据接收通常启动一个无限循环执行的线程中,当连接断开时,才停止接收线程
/**
* 收取数据线程
*/
private class RecivedDataThread extends Thread {
@Override
public void run() {
while (isConnected()) {
try {
byte data[] = readData();
if (data != null) {
onRecivedData(data);
}
Thread.sleep(1);
} catch (Exception e) {
e.printStackTrace();
deviceConnected=false;
closeUsbPort();
}
}
recivedDataThread = null;
}
}
@Override
protected byte[] readData() throws IOException, InterruptedException {
if (mInputStream == null) {
return null;
}
int length = mInputStream.available();
if (length > 1) {
byte[] temp = new byte[length];
int result = mInputStream.read(temp);
if (result > 0) {
return temp;
}
}
if (delayTime > 0) {
Thread.sleep(delayTime);
}
return null;
}
1.1.6 设备断开
设备断开的时刻,意味着资源的释放,重置为未连接的状态,为了下一次连接做准备
private void closeSocketConnect() {
mOutputStream = null;
try {
if (null != btSocket) {
if (btSocket.isConnected()) {
btSocket.close();
btSocket = null;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
1.2 低功耗蓝牙(蓝牙4.0/BLE 蓝牙)
在Android4.3系统之后,Android支持了蓝牙4.0。它最主要的特点是低功耗,普及率高。主要针对智能穿戴设备。
BLE蓝牙与经典蓝牙的区别是连接方式与数据收发的方式
核心API:
private BluetoothManager mBluetoothManager = null;
private BluetoothAdapter mAdapter = null;
private BluetoothGattService mBTService = null;
protected BluetoothGatt mBluetoothGatt = null;
protected BluetoothGattCharacteristic mBTValueCharacteristic = null;
@Override
public void init(Context context) {
mContext = context;
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
}
if (mAdapter == null) {
mAdapter = mBluetoothManager.getAdapter();
}
if (!mAdapter.isEnabled()) {
mAdapter.enable();
}
setScanDuring(Build.VERSION.SDK_INT >= 24 ? 6000 : 4000);
}
1.2.1 设备连接方式
@Override
protected void scanDevice() {
mAdapter.startLeScan(mDeviceFoundCallback);
}
private BluetoothAdapter.LeScanCallback mDeviceFoundCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
Log.d("mDeviceFoundCallback","device:"+device.getAddress());
if (deviceInfo != null && ("" + device.getAddress()).equals(deviceInfo.getMac())) {
pauseDiscovery();
connecting();
_closeConn();
Log.d("mDeviceFoundCallback", "停止扫描开始连接");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mBluetoothGatt = device.connectGatt(mContext, true, mBleCallback, BluetoothDevice.TRANSPORT_LE);
} else {
mBluetoothGatt = device.connectGatt(mContext, true, mBleCallback);
}
if (mBluetoothGatt == null) {
connectionError(-9, "蓝牙连接异常");
Log.d("mDeviceFoundCallback", "蓝牙连接异常");
}
}
}
};
1.2.2 设备连接方式
private final BluetoothGattCallback mBleCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if ((!isConnected() && !isConnecting())
|| deviceInfo == null
|| gatt.getDevice() == null
|| !(deviceInfo.getMac()+"").equals(gatt.getDevice().getAddress())) {
return;
}
Log.d("mDeviceFoundCallback","newState:"+newState);
if (newState == BluetoothProfile.STATE_CONNECTED && isConnecting()) {
Log.d("mDeviceFoundCallback","蓝牙连上了");
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.d("mDeviceFoundCallback","蓝牙断开了STATE_DISCONNECTED");
if (isConnected()) {
_closeConn();
disconnected();
}
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS && gatt.getDevice().getAddress().equals(deviceInfo.getMac())) {
initService();
}
}
/**
* 接收到数据
* @param gatt
* @param characteristic
*/
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
byte[] data = characteristic.getValue();
// Log.w("ble_data_h", ByteUtil.bytesToHexString(data));
if (isConnected() && data != null && data.length > 0) {
recivedBLEData(data);
}
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
byte[] data = characteristic.getValue();
if (isConnected() && data != null) {
Log.w("ble_data_h----", ByteUtil.bytesToHexString(data));
recivedBLEData(data);
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {//写入成功
onDataSended(characteristic.getValue());
} else if (status == BluetoothGatt.GATT_FAILURE) {
onSendDataError(status, "发送数据失败");
} else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
onSendDataError(status, "没权限");
}
};
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
}
};