蓝牙4.0
2016-05-25 17:09
281 查看
网上关于蓝牙4.0的讲解:http://www.2cto.com/kf/201411/349575.html
http://blog.csdn.net/changemyself/article/details/8454633
大家贡献的demo 下载 :http://download.csdn.net/detail/lqw770737185/8116019
2 . 确认完移动端有蓝牙模块后,接着判断支持蓝牙4.0 还是2.0 ;
3 . 确认移动端是支持蓝牙4.0 后,打开蓝牙,开启扫描,查找指定设备 , 查找到我们的设备后,关闭蓝牙扫描,这样可以减低功耗;
4 . 查找到我们的设备后,开始连接,通过 BluetoothGattCallback 接口的onConnectionStateChange方法我们可以确认此时的连接状态(通过这个状态可以做出提示,提高友好度),连接设备之后, onServicesDiscovered(BluetoothGatt gatt, int status) 这个方法会返回两个参数,status 表示此时的连接状态,if(status==BluetoothGatt.GATT_SUCCESS ),表示连接成功,并且发现了远程设备的services,这个时候我们就可以做自己的操作了,比如可以向自己的设备写入数据,例如发出开始的命令;
5 . 发送命名,我们需要知道service所包含的某一个characteristic的uuid,因为service是一个characteristic的集合,如果不知道那么就遍历characteristic集合,给所有的characteristic发送开始的命令(这里要提醒一下:遍历写入的时候要加延迟,不然很可能写入失败,我掉过的坑啊~~),并给每一个characteristic设备添加setCharacteristicNotification,表示给当前这个characteristic设置提醒,那么当指定的这个characteristic的值发生变化后,就会回调 onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)方法,在这里接收蓝牙回传数据,一般到了这里我们就已经可以拿到需要的数据了,接下来就是读取数据,通过bluetoothGatt.readCharacteristic(characteristic),characteristic已经被读取后,会回调onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status),最后把characteristic解析就是我们需要的数据了,当然,如果这还不是你需要的(可能你的设备需要进行几次交互),那么可以通过判断来决定是否再次写入
6 . 最后测量完之后,不要忘了关闭蓝牙连接
应用:
http://blog.csdn.net/changemyself/article/details/8454633
大家贡献的demo 下载 :http://download.csdn.net/detail/lqw770737185/8116019
目前主流手机蓝牙基本已经是4.0 及以上了 , 网上对于蓝牙4.0的讲解也有不少,有的已经深入到刨祖坟的地步,虽然讲的很详细,但是我看的也是云里雾里(原谅我太蠢~~~),这里打算先理清整个工作流程,后面再贴上我封装的蓝牙4.0模块(官方demo是通过广播来写,本人喜欢用接口)。
蓝牙4.0整个工作流程:
1 . 对于需要连接蓝牙设备的移动端,首先需要判断是否具有蓝牙功能(有的话就打开蓝牙),要不然你的设备再牛客户没办法用,也是白搭;2 . 确认完移动端有蓝牙模块后,接着判断支持蓝牙4.0 还是2.0 ;
/** * 打开蓝牙 * @return */ @SuppressLint("NewApi") private boolean EnableBle() { boolean enable = false; // BluetoothManager在Android4.3以上支持(API level 18)。 BluetoothManager bluetoothManager=(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); bluetoothadapter=bluetoothManager.getAdapter(); //开启蓝牙 if(bluetoothadapter!=null && SupportBle()){ bluetoothadapter.enable(); enable=true; }else if(bluetoothadapter==null){ ToastMore("没有检测到蓝牙设备"); enable=false; }else if(!SupportBle()){ ToastMore("本设备不支持蓝牙4.0"); enable=false; } return enable; } /** * 检查设备是否支持蓝牙4.0 * @return */ public boolean SupportBle(){ if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){ return true; } return false; }
3 . 确认移动端是支持蓝牙4.0 后,打开蓝牙,开启扫描,查找指定设备 , 查找到我们的设备后,关闭蓝牙扫描,这样可以减低功耗;
/**是否开始搜索设备 * @param * enable :是否搜索 * devicename: 搜索到该设备名 停止搜索 devicename==null 默认搜索1分钟 * */ public void SearchDevice(boolean enable,String devicename){ this.devicename=devicename; if(enable){ ToastMore("开始扫描"); continue_search=true; //查找特定设备 //bluetoothadapter.startLeScan(serviceUuids, callback); if(devicename==null||devicename.equals("")){ new Handler().postDelayed(new Runnable() { @Override public void run() { continue_search=false; bluetoothadapter.stopLeScan(callback); } },60000); } //开始扫描 bluetoothadapter.startLeScan(callback); }else{ ToastMore("停止扫描"); continue_search=false; //停止扫描 bluetoothadapter.stopLeScan(callback); } } /** * Device scan callback. 4.0 callback 蓝牙搜索到设备会回调该方法 搜索时,只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索 */ private BluetoothAdapter.LeScanCallback callback=new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { ((MainActivity)context).runOnUiThread(new Runnable() { public void run() { //找到指定设备停止扫描 LogMore("扫描到设备:"+device.getName()); if(continue_search){ if(devicename.equals(device.getName())){ LogMore("已经扫描到设备:"+device.getName()); //停止扫描 SearchDevice(false, null); } } } }); } };
4 . 查找到我们的设备后,开始连接,通过 BluetoothGattCallback 接口的onConnectionStateChange方法我们可以确认此时的连接状态(通过这个状态可以做出提示,提高友好度),连接设备之后, onServicesDiscovered(BluetoothGatt gatt, int status) 这个方法会返回两个参数,status 表示此时的连接状态,if(status==BluetoothGatt.GATT_SUCCESS ),表示连接成功,并且发现了远程设备的services,这个时候我们就可以做自己的操作了,比如可以向自己的设备写入数据,例如发出开始的命令;
5 . 发送命名,我们需要知道service所包含的某一个characteristic的uuid,因为service是一个characteristic的集合,如果不知道那么就遍历characteristic集合,给所有的characteristic发送开始的命令(这里要提醒一下:遍历写入的时候要加延迟,不然很可能写入失败,我掉过的坑啊~~),并给每一个characteristic设备添加setCharacteristicNotification,表示给当前这个characteristic设置提醒,那么当指定的这个characteristic的值发生变化后,就会回调 onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)方法,在这里接收蓝牙回传数据,一般到了这里我们就已经可以拿到需要的数据了,接下来就是读取数据,通过bluetoothGatt.readCharacteristic(characteristic),characteristic已经被读取后,会回调onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status),最后把characteristic解析就是我们需要的数据了,当然,如果这还不是你需要的(可能你的设备需要进行几次交互),那么可以通过判断来决定是否再次写入
/**连接设备后回调*/ private BluetoothGattCallback Gattcallback=new BluetoothGattCallback() { /**连接状态发生改变*/ @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if(status==BluetoothProfile.STATE_CONNECTED){ LogMore("已经连接"); }else if(status==BluetoothProfile.STATE_CONNECTING){ LogMore("正在连接"); }else if(status==BluetoothProfile.STATE_DISCONNECTED){ LogMore("已经断开"); }else if(status==BluetoothProfile.STATE_CONNECTING){ LogMore("正在断开"); } }; /**发现sevice*/ @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { //设备连接成功 if(status==BluetoothGatt.GATT_SUCCESS){ vble.WriteDatatoBle(getSupportedGattServices()); }else{ LogMore("onServicesDiscovered+"+status+"-->"+gatt); } } /**读取数据*/ @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if(status==BluetoothGatt.GATT_SUCCESS){ //解析数据 AnalysisBleData(characteristic); } } /**检测用户向蓝牙写数据的状态 */ @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { } /**接收蓝牙回传数据*/ @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { //读取 ReadData(characteristic); } };
6 . 最后测量完之后,不要忘了关闭蓝牙连接
/**断开连接*/ public void disconnect(){ if(bluetoothadapter!=null &&bluetoothGatt !=null){ bluetoothGatt.disconnect(); LogMore("disconnect"); } } /**关闭连接*/ public void closeconnect(){ if(bluetoothadapter!=null &&bluetoothGatt !=null){ bluetoothGatt.close(); bluetoothGatt=null; LogMore("close"); } }
上面已经讲完了整个流程,下面贴出整个工具类:
import java.util.List; import java.util.UUID; import com.siheal.bledevice66b6b5.view.MainActivity; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCallback; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.content.pm.PackageManager; import android.os.Handler; import android.util.Log; import android.widget.Toast; public class BluetoothHandle { private VBle vble; private Context context; private BluetoothAdapter bluetoothadapter; /**指定要搜索的设备名*/ private String devicename; /**记录上次连接过的蓝牙地址*/ private String exist_device_address; private BluetoothGatt bluetoothGatt; /** * 蓝牙心率解析uuid */ private static UUID UUID_HEART_RATE_MEASUREMENT=UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb"); private final String TAG = BluetoothHandle.class.getSimpleName(); /** * 用于处理数据的接口 */ public interface VBle { /**设置测量结果*/ void SetMeasureData(String data,BluetoothGattCharacteristic characteristic); /** * 向蓝牙写入数据 * @param supportedGattServices */ void WriteDatatoBle(List<BluetoothGattService> supportedGattServices); } public BluetoothHandle(Context context) { vble=(VBle) context; this.context=context; } /** * 打开蓝牙 * @return */ @SuppressLint("NewApi") public boolean EnableBle() { boolean enable = false; // BluetoothManager在Android4.3以上支持(API level 18)。 BluetoothManager bluetoothManager=(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); bluetoothadapter=bluetoothManager.getAdapter(); //开启蓝牙 if(bluetoothadapter!=null && SupportBle()){ bluetoothadapter.enable(); enable=true; }else if(bluetoothadapter==null){ ToastMore("没有检测到蓝牙设备"); enable=false; }else if(!SupportBle()){ ToastMore("本设备不支持蓝牙4.0"); enable=false; } return enable; } /** * 检查设备是否支持蓝牙4.0 * @return */ public boolean SupportBle(){ if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){ return true; } return false; } /**是否开始搜索设备 * @param * enable :是否搜索 * devicename: 搜索到该设备名 停止搜索 devicename==null 默认搜索1分钟 * */ public void SearchDevice(boolean enable,String devicename){ this.devicename=devicename; if(enable){ ToastMore("开始扫描"); //bluetoothadapter.startLeScan(serviceUuids, callback);//查找特定设备 if(devicename==null||devicename.equals("")){ new Handler().postDelayed(new Runnable() { @Override public void run() { bluetoothadapter.stopLeScan(callback); } },60000); } bluetoothadapter.startLeScan(callback); }else{ ToastMore("停止扫描"); bluetoothadapter.stopLeScan(callback); } } /** * Device scan callback. 4.0 callback 蓝牙搜索到设备会回调该方法 搜索时,只能搜索传统蓝牙设备或者BLE设备,两者完全独立,不可同时被搜索 */ private BluetoothAdapter.LeScanCallback callback=new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { ((MainActivity)context).runOnUiThread(new Runnable() { public void run() { //找到指定设备停止扫描 LogMore("扫描到设备:"+device.getName()); if(devicename.equals(device.getName())){ LogMore("已经扫描到设备:"+device.getName()); SearchDevice(false, null); //当查找到指定设备后 开始连接 BluetoothHandle.this.connect(device); } } }); } }; /** * 连接设备 * @param device * @return */ @SuppressWarnings("unused") public boolean connect(BluetoothDevice device){ LogMore("正在连接设备:"+device.getName()); String deviceaddress=device.getAddress(); if(exist_device_address!=null&&deviceaddress.equals(exist_device_address)&&bluetoothGatt!=null){ LogMore("Trying to use an existing mBluetoothGatt for connection."); if(bluetoothGatt.connect()){ LogMore("connection success"); return true; }else{ return false; } } if(device!=null){ //三个参数:a Context object, autoConnect(boolean 类型的,确定 是否自动连接) //and a reference to a BluetoothGattCallback bluetoothGatt=device.connectGatt(context,false, Gattcallback); }else{ LogMore("Device not found. Unable to connect."); return false; } return true; } /**连接设备后回调*/ private BluetoothGattCallback Gattcallback=new BluetoothGattCallback() { /**连接状态发生改变*/ @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if(status==BluetoothProfile.STATE_CONNECTED){ LogMore("已经连接"); }else if(status==BluetoothProfile.STATE_CONNECTING){ LogMore("正在连接"); }else if(status==BluetoothProfile.STATE_DISCONNECTED){ LogMore("已经断开"); }else if(status==BluetoothProfile.STATE_CONNECTING){ LogMore("正在断开"); } }; /**发现sevice*/ @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { //设备连接成功 if(status==BluetoothGatt.GATT_SUCCESS){ vble.WriteDatatoBle(getSupportedGattServices()); }else{ LogMore("onServicesDiscovered+"+status+"-->"+gatt); } } /**读取数据*/ @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { if(status==BluetoothGatt.GATT_SUCCESS){ //读取数据 LogMore("onCharacteristicRead+"+characteristic.getUuid().toString()); AnalysisBleData(characteristic); } } /**检测用户向蓝牙写数据的状态 */ @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { } /**接收蓝牙回传数据*/ @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { ReadData(characteristic); //AnalysisBleData(characteristic); } }; /** * Retrieves a list of supported GATT services on the connected device. This should be * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully. * * @return A {@code List} of supported services. * <p> * 获取远程设备所支持的services * <p> * services : Characteristic的集合。例如一个service叫做“Heart Rate Monitor”, * 它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement"的Characteristic。 */ private List<BluetoothGattService> getSupportedGattServices() { if (bluetoothGatt == null) return null; return bluetoothGatt.getServices(); } /** * 数据解析按照蓝牙心率测量配置文件规格进行 * @param characteristic */ protected void AnalysisBleData(BluetoothGattCharacteristic characteristic) { String mdata=null; // 这是心率测量配置文件。 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, "Heart rate format UINT16."); } else { format = BluetoothGattCharacteristic.FORMAT_UINT8; Log.d(TAG, "Heart rate format UINT8."); } final int heartRate = characteristic.getIntValue(format, 1); Log.d(TAG, String.format("Received heart rate: %d", heartRate)); mdata=String.valueOf(heartRate); } else { // 对于所有其他的配置文件,用十六进制格式写数据 final byte[] data = characteristic.getValue(); if (data != null && data.length > 0) { final StringBuilder stringBuilder = new StringBuilder(data.length); for(byte byteChar : data) stringBuilder.append(String.format("%02X ", byteChar)); mdata=new String(data) + "\n" +stringBuilder.toString(); } } vble.SetMeasureData(mdata,characteristic); } /** * 设置当指定characteristic值变化时,发出通知 * <p> * 当 其发生变化时会使 onCharacteristicChanged()回调被触发*/ public void SetCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled){ if(bluetoothadapter!=null&&bluetoothGatt!=null){ bluetoothGatt.setCharacteristicNotification(characteristic, enabled); BluetoothGattDescriptor descriptor=characteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); if(descriptor!=null){ LogMore("set descriptor" + descriptor + descriptor.getValue()); if(enabled){ descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); } else{ descriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); } bluetoothGatt.writeDescriptor(descriptor); } } } /** * 向设备写入数据 * @param characteristic */ public void WriteData(BluetoothGattCharacteristic characteristic){ if(bluetoothadapter!=null&&bluetoothGatt!=null){ bluetoothGatt.writeCharacteristic(characteristic); } } /**读取蓝牙数据 * @param characteristic */ public void ReadData(BluetoothGattCharacteristic characteristic){ if(bluetoothadapter!=null&&bluetoothGatt!=null){ bluetoothGatt.readCharacteristic(characteristic); } } /**断开连接*/ public void disconnect(){ if(bluetoothadapter!=null &&bluetoothGatt !=null){ bluetoothGatt.disconnect(); LogMore("disconnect"); } } /**关闭连接*/ public void closeconnect(){ if(bluetoothadapter!=null &&bluetoothGatt !=null){ bluetoothGatt.close(); bluetoothGatt=null; LogMore("close"); } } //----------------------------------------------- private void ToastMore(String string){ Toast.makeText(context, string,Toast.LENGTH_SHORT).show(); } private void LogMore(String string){ Log.i(TAG,string); } }
应用:
import java.util.List; import com.siheal.bledevice66b6b5.R; import com.siheal.bledevice66b6b5.presenter.BluetoothHandle; import com.siheal.bledevice66b6b5.presenter.BluetoothHandle.VBle; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.app.Activity; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattService; import android.widget.TextView; public class MainActivity extends Activity implements VBle , OnClickListener { private TextView measureData; /**蓝牙工具类*/ private BluetoothHandle blehandle; /**ָ指定需要查找的设备名*/ private String assigndevicename="BT05"; /** 是否允许测量*/ private boolean allowmeasure=false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); blehandle=new BluetoothHandle(this); measureData=(TextView) findViewById(R.id.measureData); findViewById(R.id.searchdevice).setOnClickListener(this); allowmeasure=blehandle.EnableBle(); } @Override protected void onResume() { super.onResume(); if(allowmeasure) blehandle.SearchDevice(true,assigndevicename); } @Override protected void onPause() { super.onPause(); if(allowmeasure){ blehandle.SearchDevice(false, null); blehandle.disconnect(); } } @Override protected void onStop() { super.onStop(); if(allowmeasure){ blehandle.SearchDevice(false, null); blehandle.closeconnect(); } } @Override public void onClick(View v) { switch (v.getId()) { case R.id.searchdevice: if(allowmeasure){ blehandle.SearchDevice(true,assigndevicename); } break; } } @Override public void WriteDatatoBle(List<BluetoothGattService> supportedGattServices) { for(BluetoothGattService getservice:supportedGattServices){ for(final BluetoothGattCharacteristic characteristic : getservice.getCharacteristics()){ new Handler().postDelayed(new Runnable() { @Override public void run() { characteristic.setValue("写入数据"); blehandle.WriteData(characteristic); } }, 150); } } } @Override public void SetMeasureData(String data, BluetoothGattCharacteristic characteristic) { if(data.contains("自己设备数据的特定标识符")){ measureData.setText(data); }else { //如果不是我们需要的那么根据需要在向设备写入 characteristic.setValue("写入数据"); blehandle.WriteData(characteristic); } } }
相关文章推荐
- iOS 添加翼支付打包上传出错 ERROR ITMS-90535
- Volley的基本用法 使用Volley加载网络图片
- android studio如何导包
- Android ColorState使用
- 普通字符串转MFC字符串函数
- Intent传值的使用
- 设计模式 - Strategy模式
- Android Studio导入银联sdk
- 高斯遥感稳像的论文
- NSOperation
- NSThread
- 谈谈数组和指针组合时,表示什么样的变量
- 环形队列的C++实现
- IOの对象流
- Substring(最长回文串)
- weblogic项目部署方式选择分析
- C#微信登录-手机网站APP应用
- ARC指南3 - @property
- ISO27001LA 学友联盟再次来袭
- CodeForces 671B Robin Hood