Android蓝牙4.0BLE开发实现对蓝牙的写入数据和读取数据
代码基本上都是官方的演示,只是通过修改获得自己想要的结果,下面就简单介绍一下自己的理解。
一,扫描BLE设备活动
检查该设备是否支持BLE设备,谷歌在Android4.3才开始支持BLE设备(晕死,很长一段时间都没有一台4.3的设备,看着程序修改了也不能测试!)。
if(!getPackageManager()。hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){ Toast.makeText(this,R.string.ble_not_supported,Toast.LENGTH_SHORT).show(); 完(); }
初始化获得一个bluetoothManager,并检测设备是否支持蓝牙
最后蓝牙管理器bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter();
//检查设备是否支持蓝牙。 if(mBluetoothAdapter == null){ Toast.makeText(this,R.string.error_bluetooth_not_supported,Toast.LENGTH_SHORT).show(); 完(); 返回; }扫描BLE设备,然后添加到ListView控件里面。
private void scanLeDevice(final boolean enable){ if(enable){ //在预定义的扫描周期之后停止扫描。 mHandler.postDelayed(new Runnable(){ @覆盖 public void run(){ mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); invalidateOptionsMenu(); } },SCAN_PERIOD); mScanning = true; mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } invalidateOptionsMenu(); }
二,蓝牙控制的服务BluetoothLeService
在这个服务里面有一个很重要的回调函数BluetoothGattCallback(),蓝牙的数据读取和状态改变都会回调这个函数。
私人最终蓝牙GattCallback mGattCallback = new BluetoothGattCallback(){ @覆盖 public void onConnectionStateChange(BluetoothGatt gatt,int status,int newState){ 字符串intentAction; //收到设备通知值(设备上报值) if(newState == BluetoothProfile.STATE_CONNECTED){ intentAction = ACTION_GATT_CONNECTED; mConnectionState = STATE_CONNECTED; broadcastUpdate(intentAction); Log.i(TAG,“连接到GATT服务器”); //尝试成功连接后发现服务。 Log.i(TAG,“尝试启动服务发现:”+ mBluetoothGatt.discoverServices()); } else if(newState == BluetoothProfile.STATE_DISCONNECTED){ intentAction = ACTION_GATT_DISCONNECTED; mConnectionState = STATE_DISCONNECTED; Log.i(TAG,“断开GATT服务器”); broadcastUpdate(intentAction); } } @覆盖 public void onServicesDiscovered(BluetoothGatt gatt,int status){ if(status == BluetoothGatt.GATT_SUCCESS){ broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED); } else { Log.w(TAG,“onServicesDiscovered received:”+ status); System.out.println(“onServicesDiscovered received:”+ status); } } @覆盖 public void onCharacteristicRead(BluetoothGatt gatt, 蓝牙功能特点, int status){ //读取到值,在这里读数据 if(status == BluetoothGatt.GATT_SUCCESS){ broadcastUpdate(ACTION_DATA_AVAILABLE,特征); } } @覆盖 public void onCharacteristicChanged(BluetoothGatt gatt, 蓝牙特征特征){ broadcastUpdate(ACTION_DATA_AVAILABLE,特征); } };在官方的演示中还使用到广播,可能是因为人大神写的,要严谨些。我一开始看的时候就得这有点麻烦,跳转的多麻烦。
private void broadcastUpdate(final String action){ 最终意图意图=新意图(动作); sendBroadcast(意向); } private void broadcastUpdate(final String action, 最终蓝牙功能特性){ 最终意图意图=新意图(动作); //这是心率测量配置文件的特殊处理。数据解析是 //按照配置文件规格执行: // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml if(UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())){ int flag = characteristic.getProperties(); int format = -1; if((flag&0x01)!= 0){ format = BluetoothGattCharacteristic.FORMAT_UINT16; Log.d(TAG,“心率格式UINT16”); } else { format = BluetoothGattCharacteristic.FORMAT_UINT8; Log.d(TAG,“心率格式UINT8”); } final int heartRate = characteristic.getIntValue(format,1); Log.d(TAG,String.format(“Received heart rate:%d”,heartRate)); intent.putExtra(EXTRA_DATA,String.valueOf(heartRate)); } else { //对于所有其他配置文件,写入以HEX格式化的数据。对于所有的文件,写入十六进制格式的文件 //这里读取到数据 final byte [] data = characteristic.getValue(); for(int i = 0; i <data.length; i ++){ System.out.println(“data ......”+ data [i]); } if(data!= null && data.length> 0){ StringBuilder stringBuilder = new StringBuilder(data.length); for(byte byteChar:data) //以十六进制的形式输出 stringBuilder.append(String.format(“%02X”,byteChar)); // intent.putExtra(EXTRA_DATA,new String(data)+“\ n”+ stringBuilder.toString()); intent.putExtra(EXTRA_DATA,new String(data)); } } sendBroadcast(意向); }发送了广播之后就肯定有广播接收器,这个是在控制蓝牙的活动中,后面再说。
还有几个重要的函数比如readCharacteristic(BluetoothGattCharacteristic characteristics)函数,读取蓝牙中数据。
public void readCharacteristic(BluetoothGattCharacteristic characteristics){ if(mBluetoothAdapter == null || mBluetoothGatt == null){ Log.w(TAG,“BluetoothAdapter未初始化”); 返回; } mBluetoothGatt.readCharacteristic(特性); }有readCharacteristic(BluetoothGattCharacteristic特征)函数,当然就有写特征(BluetoothGattCharacteristic特征),向蓝牙中写入数据。
public void writeCharacteristic(BluetoothGattCharacteristic characteristics){ if(mBluetoothAdapter == null || mBluetoothGatt == null){ Log.w(TAG,“BluetoothAdapter未初始化”); 返回; } mBluetoothGatt.writeCharacteristic(特性); }另外在这个服务中还有其他的一些函数例如初始化initialize()函数,连接蓝牙函数connect(final String address),断开蓝牙连接函数disconnect()等
三,蓝牙控制DeviceControlActivity
扫描到蓝牙设备之后就是对蓝牙进行自己需要的控制,比如写数据,读数据,获取设备信息,设备电量等。
在服务中讲到有一个广播,广播接收器就在这个活动中,通过不同的动作做出相应的操作。
注册的几种事件
私有静态IntentFilter makeGattUpdateIntentFilter(){ IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED); intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE); return intentFilter; }
//处理由服务发射的各种事件。处理服务所激发的各种事件 // ACTION_GATT_CONNECTED:connected to a GATT server。连接一个GATT服务 // ACTION_GATT_DISCONNECTED:与GATT服务器断开连接。从GATT服务中断开连接 // ACTION_GATT_SERVICES_DISCOVERED:found GATT services。查找GATT服务 // ACTION_DATA_AVAILABLE:从设备接收数据。这可能是阅读的结果 //或通知操作。从服务中接受数据 BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver(){ @覆盖 public void onReceive(Context context,Intent intent){ final String action = intent.getAction(); if(BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)){ mConnected = true; updateConnectionState(R.string.connected); invalidateOptionsMenu(); } else if(BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)){ mConnected = false; updateConnectionState(R.string.disconnected); invalidateOptionsMenu(); clearUI(); } //发现有可支持的服务 else if(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)){ //写数据的服务和特征 mnotyGattService = mBluetoothLeService.getSupportedGattServices(UUID.fromString(“0000ffe5-0000-1000-8000-00805f9b34fb”)); 特征= mnotyGattService.getCharacteristic(UUID.fromString(“0000ffe9-0000-1000-8000-00805f9b34fb”)); //读数据的服务和特征 readMnotyGattService = mBluetoothLeService.getSupportedGattServices(UUID.fromString(“0000ffe0-0000-1000-8000-00805f9b34fb”)); readCharacteristic = readMnotyGattService.getCharacteristic(UUID.fromString(“0000ffe4-0000-1000-8000-00805f9b34fb”)); } //显示数据 else if(BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)){ //将数据显示在mDataField上 String data = intent.getStringExtra(BluetoothLeService.EXTRA_DATA); System.out.println(“data ----”+ data); displayData(数据); } } };在发现了有可支持的服务之后会回调服务中的onServicesDiscovered()函数,并发送广播,在官方的演示中发现了可用的服务之后,就查找该BLE设备支持的所有服务和特性,在这里不需要查找所有的服务,只需要向蓝牙写数据和读取数据的 服务和特征的UUID即可。通过查询低功耗蓝牙(BLE)的数据手册可以得到所需要的UUID。
有了这两个服务和特征的 UUID,就可以对蓝牙发送数据,并发出通知(当写数据发生改变时发出)。
<span style =“;”> //写数据的服务和特征 mnotyGattService = mBluetoothLeService.getSupportedGattServices(UUID.fromString(“0000ffe5-0000-1000-8000-00805f9b34fb”)); 特征= mnotyGattService.getCharacteristic(UUID.fromString(“0000ffe9-0000-1000-8000-00805f9b34fb”)); //读数据的服务和特征 readMnotyGattService = mBluetoothLeService.getSupportedGattServices(UUID.fromString(“0000ffe0-0000-1000-8000-00805f9b34fb”)); readCharacteristic = readMnotyGattService.getCharacteristic(UUID.fromString(“0000ffe4-0000-1000-8000-00805f9b34fb”)); </ span>得到这两个服务和特性就可以向蓝牙发送数据了。
private void read(){ //mBluetoothLeService.readCharacteristic(readCharacteristic); // readCharacteristic的数据发生变化,发出通知 mBluetoothLeService.setCharacteristicNotification(readCharacteristic,true); //Toast.makeText(this,“读成功”,Toast.LENGTH_SHORT).show(); }检测readCharacteristic的数据发生变化,发出通知。
向蓝牙发送数据。
读(); final int charaProp = characteristic.getProperties(); //如果该字符可写 if((charaProp | BluetoothGattCharacteristic.PROPERTY_READ)> 0){ //如果有关于特征的活动通知,请清除 //它首先,所以它不会更新用户界面上的数据字段。 if(mNotifyCharacteristic!= null){ mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic,false); mNotifyCharacteristic = null; } //读取数据,数据将在回调函数中 //mBluetoothLeService.readCharacteristic(characteristic); byte [] value = new byte [20]; 值[0] =(字节)0x00; 如果(edittext_input_value.getText()。的toString()。等于( “”)){ Toast.makeText(getApplicationContext(),“请输入!”,Toast.LENGTH_SHORT).show(); 返回; }其他{ WriteBytes = edittext_input_value.getText()。toString()。getBytes(); characteristic.setValue(value [0],BluetoothGattCharacteristic.FORMAT_UINT8,0); characteristic.setValue(WriteBytes); mBluetoothLeService.writeCharacteristic(特性); Toast.makeText(getApplicationContext(),“写入成功!”,Toast.LENGTH_SHORT).show(); } } if((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY)> 0){ mNotifyCharacteristic =特征; mBluetoothLeService.setCharacteristicNotification(特征,真实); } edittext_input_value.setText( “”); }一旦数据发生改变,就会发出通知,通知发出后就会调用下面的函数并发出广播。
@覆盖 public void onCharacteristicChanged(BluetoothGatt gatt, 蓝牙特征特征){ broadcastUpdate(ACTION_DATA_AVAILABLE,特征); }