分享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蓝牙技术有所帮助。