分享Android 蓝牙4.0(ble)开发的解决方案
最近,随着智能穿戴式设备、智能医疗以及智能家居的普及,蓝牙开发在移动开中显得非常的重要。由于公司需要,研究了一下,蓝牙4.0在Android中的应用。
以下是我的一些总结。
1.先介绍一下关于蓝牙4.0中的一些名词吧:
(1)、GATT(GnericAttibute Profile)
通过ble连接,读写属性类小数据Profile通用的规范。现在所有的ble应用Profile 都是基于GATT
(2)、ATT(AttributeProtocal)
GATT是基于ATTPotocal的ATT针对BLE设备专门做的具体就是传输过程中使用尽量少的数据,每个属性都有个唯一的UUID,属性chartcteristicsandService的形式传输。
(3)、Service是Characteristic的集合。
(4)、Characteristic特征类型。
比如,有个蓝牙ble的血压计。他可能包括多个Servvice,每个Service有包括多个Characteristic
注意:蓝牙ble只能支持Android4.3以上的系统SDK>=18
2.以下是开发的步骤:
2.1首先获取BluetoothManager
BluetoothManagerbluetoothManager=(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
2.2获取BluetoothAdapter
BluetoothAdaptermBluetoothAdapter=bluetoothManager.getAdapter();
2.3创建BluetoothAdapter.LeScanCallback
privateBluetoothAdapter.LeScanCallbackmLeScanCallback=newBluetoothAdapter.LeScanCallback(){
@Override
publicvoidonLeScan(finalBluetoothDevicedevice,intrssi,finalbyte[]scanRecord){
runOnUiThread(newRunnable(){
@Override
publicvoidrun(){
try{
Stringstruuid=NumberUtils.bytes2HexString(NumberUtils.reverseBytes(scanRecord)).replace("-","").toLowerCase();
if(device!=null&&struuid.contains(DEVICE_UUID_PREFIX.toLowerCase())){
mBluetoothDevices.add(device);
}
}catch(Exceptione){
e.printStackTrace();
}
}
});
}
};
2.4.开始搜索设备。
mBluetoothAdapter.startLeScan(mLeScanCallback);
2.5.BluetoothDevice 描述了一个蓝牙设备提供了getAddress()设备Mac地址,getName()设备的名称。
2.6开始连接设备
/**
*ConnectstotheGATTserverhostedontheBluetoothLEdevice.
*
*@paramaddress
*Thedeviceaddressofthedestinationdevice.
*
*@returnReturntrueiftheconnectionisinitiatedsuccessfully.The
*connectionresultisreportedasynchronouslythroughthe
*{@codeBluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt,int,int)}
*callback.
*/
publicbooleanconnect(finalStringaddress){
if(mBluetoothAdapter==null||address==null){
Log.w(TAG,"BluetoothAdapternotinitializedorunspecifiedaddress.");
returnfalse;
}
//Previouslyconnecteddevice.Trytoreconnect.(先前连接的设备。尝试重新连接)
if(mBluetoothDeviceAddress!=null&&address.equals(mBluetoothDeviceAddress)&&mBluetoothGatt!=null){
Log.d(TAG,"TryingtouseanexistingmBluetoothGattforconnection.");
if(mBluetoothGatt.connect()){
mConnectionState=STATE_CONNECTING;
returntrue;
}else{
returnfalse;
}
}
finalBluetoothDevicedevice=mBluetoothAdapter.getRemoteDevice(address);
if(device==null){
Log.w(TAG,"Devicenotfound.Unabletoconnect.");
returnfalse;
}
//Wewanttodirectlyconnecttothedevice,sowearesettingthe
//autoConnect
//parametertofalse.
mBluetoothGatt=device.connectGatt(this,false,mGattCallback);
Log.d(TAG,"Tryingtocreateanewconnection.");
mBluetoothDeviceAddress=address;
mConnectionState=STATE_CONNECTING;
returntrue;
}
2.7连接到设备之后获取设备的服务(Service)和服务对应的Characteristic。
//DemonstrateshowtoiteratethroughthesupportedGATT
//Services/Characteristics.
//Inthissample,wepopulatethedatastructurethatisboundtothe
//ExpandableListView
//ontheUI.
privatevoiddisplayGattServices(List<BluetoothGattService>gattServices){
if(gattServices==null)
return;
Stringuuid=null;
ArrayList<HashMap<String,String>>gattServiceData=newArrayList<>();
ArrayList<ArrayList<HashMap<String,String>>>gattCharacteristicData=newArrayList<>();
mGattCharacteristics=newArrayList<>();
//LoopsthroughavailableGATTServices.
for(BluetoothGattServicegattService:gattServices){
HashMap<String,String>currentServiceData=newHashMap<>();
uuid=gattService.getUuid().toString();
if(uuid.contains("ba11f08c-5f14-0b0d-1080")){//服务的uuid
//System.out.println("thisgattServiceUUIDis:"+gattService.getUuid().toString());
currentServiceData.put(LIST_NAME,"Service_OX100");
currentServiceData.put(LIST_UUID,uuid);
gattServiceData.add(currentServiceData);
ArrayList<HashMap<String,String>>gattCharacteristicGroupData=newArrayList<>();
List<BluetoothGattCharacteristic>gattCharacteristics=gattService.getCharacteristics();
ArrayList<BluetoothGattCharacteristic>charas=newArrayList<>();
//LoopsthroughavailableCharacteristics.
for(BluetoothGattCharacteristicgattCharacteristic:gattCharacteristics){
charas.add(gattCharacteristic);
HashMap<String,String>currentCharaData=newHashMap<>();
uuid=gattCharacteristic.getUuid().toString();
if(uuid.toLowerCase().contains("cd01")){
currentCharaData.put(LIST_NAME,"cd01");
}elseif(uuid.toLowerCase().contains("cd02")){
currentCharaData.put(LIST_NAME,"cd02");
}elseif(uuid.toLowerCase().contains("cd03")){
currentCharaData.put(LIST_NAME,"cd03");
}elseif(uuid.toLowerCase().contains("cd04")){
currentCharaData.put(LIST_NAME,"cd04");
}else{
currentCharaData.put(LIST_NAME,"write");
}
currentCharaData.put(LIST_UUID,uuid);
gattCharacteristicGroupData.add(currentCharaData);
}
mGattCharacteristics.add(charas);
gattCharacteristicData.add(gattCharacteristicGroupData);
mCharacteristicCD01=gattService.getCharacteristic(UUID.fromString("0000cd01-0000-1000-8000-00805f9b34fb"));
mCharacteristicCD02=gattService.getCharacteristic(UUID.fromString("0000cd02-0000-1000-8000-00805f9b34fb"));
mCharacteristicCD03=gattService.getCharacteristic(UUID.fromString("0000cd03-0000-1000-8000-00805f9b34fb"));
mCharacteristicCD04=gattService.getCharacteristic(UUID.fromString("0000cd04-0000-1000-8000-00805f9b34fb"));
mCharacteristicWrite=gattService.getCharacteristic(UUID.fromString("0000cd20-0000-1000-8000-00805f9b34fb"));
//System.out.println("=======================SetNotification==========================");
//开始顺序监听,第一个:CD01
mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD01,true);
mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD02,true);
mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD03,true);
mBluetoothLeService.setCharacteristicNotification(mCharacteristicCD04,true);
}
}
}
2.8获取到特征之后,找到服务中可以向下位机写指令的特征,向该特征写入指令。
publicvoidwirteCharacteristic(BluetoothGattCharacteristiccharacteristic){
if(mBluetoothAdapter==null||mBluetoothGatt==null){
Log.w(TAG,"BluetoothAdapternotinitialized");
return;
}
mBluetoothGatt.writeCharacteristic(characteristic);
}
2.9写入成功之后,开始读取设备返回来的数据。
privatefinalBluetoothGattCallbackmGattCallback=newBluetoothGattCallback(){
@Override
publicvoidonConnectionStateChange(BluetoothGattgatt,intstatus,intnewState){
StringintentAction;
//System.out.println("=======status:"+status);
if(newState==BluetoothProfile.STATE_CONNECTED){
intentAction=ACTION_GATT_CONNECTED;
mConnectionState=STATE_CONNECTED;
broadcastUpdate(intentAction);
Log.i(TAG,"ConnectedtoGATTserver.");
//Attemptstodiscoverservicesaftersuccessfulconnection.
Log.i(TAG,"Attemptingtostartservicediscovery:"+mBluetoothGatt.discoverServices());
}elseif(newState==BluetoothProfile.STATE_DISCONNECTED){
intentAction=ACTION_GATT_DISCONNECTED;
mConnectionState=STATE_DISCONNECTED;
Log.i(TAG,"DisconnectedfromGATTserver.");
broadcastUpdate(intentAction);
}
}
@Override
publicvoidonServicesDiscovered(BluetoothGattgatt,intstatus){
if(status==BluetoothGatt.GATT_SUCCESS){
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
}else{
Log.w(TAG,"onServicesDiscoveredreceived:"+status);
}
}
//从特征中读取数据
@Override
publicvoidonCharacteristicRead(BluetoothGattgatt,BluetoothGattCharacteristiccharacteristic,intstatus){
//System.out.println("onCharacteristicRead");
if(status==BluetoothGatt.GATT_SUCCESS){
broadcastUpdate(ACTION_DATA_AVAILABLE,characteristic);
}
}
//向特征中写入数据
@Override
publicvoidonCharacteristicWrite(BluetoothGattgatt,BluetoothGattCharacteristiccharacteristic,intstatus){
//System.out.println("--------writesuccess-----status:"+status);
}
/*
*whenconnectedsuccessfullywillcallbackthismethodthismethodcan
*dealwithsendpasswordordataanalyze
*当连接成功将回调该方法
*/
@Override
publicvoidonCharacteristicChanged(BluetoothGattgatt,BluetoothGattCharacteristiccharacteristic){
broadcastUpdate(ACTION_DATA_AVAILABLE,characteristic);
if(characteristic.getValue()!=null){
//System.out.println(characteristic.getStringValue(0));
}
//System.out.println("--------onCharacteristicChanged-----");
}
@Override
publicvoidonDescriptorWrite(BluetoothGattgatt,BluetoothGattDescriptordescriptor,intstatus){
//System.out.println("onDescriptorWriteonDescriptorWrite="+status+",descriptor="+descriptor.getUuid().toString());
UUIDuuid=descriptor.getCharacteristic().getUuid();
if(uuid.equals(UUID.fromString("0000cd01-0000-1000-8000-00805f9b34fb"))){
broadcastUpdate(ACTION_CD01NOTIDIED);
}elseif(uuid.equals(UUID.fromString("0000cd02-0000-1000-8000-00805f9b34fb"))){
broadcastUpdate(ACTION_CD02NOTIDIED);
}elseif(uuid.equals(UUID.fromString("0000cd03-0000-1000-8000-00805f9b34fb"))){
broadcastUpdate(ACTION_CD03NOTIDIED);
}elseif(uuid.equals(UUID.fromString("0000cd04-0000-1000-8000-00805f9b34fb"))){
broadcastUpdate(ACTION_CD04NOTIDIED);
}
}
@Override
publicvoidonReadRemoteRssi(BluetoothGattgatt,intrssi,intstatus){
//System.out.println("rssi="+rssi);
}
};
----------------------------------------------
//从特征中读取数据
@Override
publicvoidonCharacteristicRead(BluetoothGattgatt,BluetoothGattCharacteristiccharacteristic,intstatus){
//System.out.println("onCharacteristicRead");
if(status==BluetoothGatt.GATT_SUCCESS){
broadcastUpdate(ACTION_DATA_AVAILABLE,characteristic);
}
}
2.10、断开连接
/**
*Disconnectsanexistingconnectionorcancelapendingconnection.The
*disconnectionresultisreportedasynchronouslythroughthe
*{@codeBluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt,int,int)}
*callback.
*/
publicvoiddisconnect(){
if(mBluetoothAdapter==null||mBluetoothGatt==null){
Log.w(TAG,"BluetoothAdapternotinitialized");
return;
}
mBluetoothGatt.disconnect();
}
2.11、数据的转换方法
//byte转十六进制字符串
publicstaticStringbytes2HexString(byte[]bytes){
Stringret="";
for(byteaByte:bytes){
Stringhex=Integer.toHexString(aByte&0xFF);
if(hex.length()==1){
hex='0'+hex;
}
ret+=hex.toUpperCase(Locale.CHINA);
}
returnret;
}
/**
*将16进制的字符串转换为字节数组
*
*@parammessage
*@return字节数组
*/
publicstaticbyte[]getHexBytes(Stringmessage){
intlen=message.length()/2;
char[]chars=message.toCharArray();
String[]hexStr=newString[len];
byte[]bytes=newbyte[len];
for(inti=0,j=0;j<len;i+=2,j++){
hexStr[j]=""+chars[i]+chars[i+1];
bytes[j]=(byte)Integer.parseInt(hexStr[j],16);
}
returnbytes;
}
大概整体就是如上的步骤,但是也是要具体根据厂家的协议来实现通信的过程。
就拿一个我们项目中的demo说一下。
一个蓝牙ble的血压计。上位机---手机 下位机--血压计
1.血压计与手机连接蓝牙之后。
2.上位机主动向下位机发送一个身份验证指令,下位机收到指令后开始给上位做应答,
3.应答成功,下位机会将测量的血压数据传送到上位机。
4.最后断开连接。
希望本文对大家学习Android蓝牙技术有所帮助。