Android Ble 4.0 蓝牙开发交互
来源:互联网 发布:网店刷销量软件 编辑:程序博客网 时间:2024/05/01 18:47
产品需求:1、app通过蓝牙连接到板子设备
2、以发报文的形式与板子设备通讯
3、当设备接受到正确的报文指令后,会将检测的数据返回
4、将返回的数据解析设置到界面显示即可
板子介绍:
准备工作:
1:、与嵌入式工程师交互(将驱动这里指串口,装在电脑上)
2、将对应线路接好
3、报文的协议文档等可先看看了解一下(这里用的是MODBUS RTU协议)
其实也就差不多这些准备(有问题可以直接问相关嵌入式人员),废话少说,下面就直接进行主题吧。。。
第一步:首先我们可以整理一下思路:
1、实现搜索功能,针对蓝牙周围设备的发现
2、对目标 设备进行连接
3、开发期间是多与串口交互(可以先实现app将数据传递串口,协议先不做考虑)
4、在实现串口向app的数据的传递(协议先不做考虑)
5、实现对数据的解析(根据协议去实现解析即可),在将数据显示即可
以上为整体的实现步骤,开发的时候在具体到细节!
第二步:防止一头雾水,我们先来简单复习一下BlueTooth相关的api
1:BuletoothAdapter
这个类的对象代表了本地的蓝牙适配器,相当于蓝牙工作流程图中的手机里的蓝牙适配器,也就是说比如这个应用程序是运行在手机上,那么手机上的蓝牙适配器就是本地蓝牙适配器。
cancelDiscovery() 根据字面意思,是取消发现,也就是说当我们正在搜索设备的时候调用这个方法将不再继续搜索
disable() 关闭蓝牙
enable() 打开蓝牙,这个方法打开蓝牙不会弹出提示,更多的时候我们需要问下用户是否打开,一下这两行代码同样是打开蓝牙,不过会提示用户:
Intemtenabler=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enabler,reCode); 同startActivity(enabler);
getAddress() 获取本地蓝牙地址
getDefaultAdapter() 获取默认BluetoothAdapter,实际上,也只有这一种方法获取BluetoothAdapter
getName() 获取本地蓝牙名称
getRemoteDevice(String address) 根据蓝牙地址获取远程蓝牙设备
getState() 获取本地蓝牙适配器当前状态(感觉可能调试的时候更需要)
isDiscovering() 判断当前是否正在查找设备,是返回true
isEnabled() 判断蓝牙是否打开,已打开返回true,否则,返回false
listenUsingRfcommWithServiceRecord(String name,UUID uuid)根据名称,UUID创建并返回BluetoothServerSocket,这是创建BluetoothSocket服务器端的第一步
startDiscovery() 开始搜索,这是搜索的第一步
2:BuletoothDevice
这个类的对象代表了远程的蓝牙设备,相当于蓝牙工作流程图中的计算机里的蓝牙适配器,也就是说比如这个应用程序是运行在手机上,那么BuletoothDevice代表了你要连接的远程的那个设备上面的蓝牙适配器。
createRfcommSocketToServiceRecord(UUIDuuid)根据UUID创建并返回一个BluetoothSocket 这个方法也是我们获取BluetoothDevice的目的——创建BluetoothSocket
3.BluetoothSocket,跟BluetoothServerSocket相对,是客户端一共5个方法,不出意外,都会用到
close(), 关闭
connect() 连接
getInptuStream() 获取输入流
getOutputStream() 获取输出流
getRemoteDevice() 获取远程设备,这里指的是获取bluetoothSocket指定连接的那个远程蓝牙设备
第三步:实现功能
3.1:开启蓝牙,判断手机是否支持蓝牙
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if(mBluetoothAdapter == null){ //不支持 return; } if(!mBluetoothAdapter.isEnabled()){ //蓝牙未开启,则开启蓝牙 Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE_BT); } //...... public void onActivityResult(int requestCode, int resultCode, Intent data){ if(requestCode == REQUEST_ENABLE_BT){ if(requestCode == RESULT_OK){ //蓝牙开启 } } }3.2:判断设备是否支持ble
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { //针对设备不支持ble,可以进行操作 Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); finish();}3.3:判断是否启用蓝牙对话框
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {switch (requestCode) {case REQUEST_ENABLE:if (resultCode == Activity.REQUEST_ENABLE_BT) { //蓝牙启用} else { //蓝牙没有启用} break;}}3.4:开始进行蓝牙设备的搜索 - 注意一点:这里不要在onCreate里面去进行搜索,会出现没有响应
private void scanLeDevice(final boolean enable) { if (enable) { // Stops scanning after a pre-defined scan period. mHandler.postDelayed(new Runnable() { @Override public void run() { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } }, SCAN_PERIOD); //在这里可以自己进行时间的设置,比如搜索10秒 mScanning = true; mBluetoothAdapter.startLeScan(mLeScanCallback); //开始搜索 } else { mScanning = false; mBluetoothAdapter.stopLeScan(mLeScanCallback);//停止搜索 } }3.5:当设备搜索到的时候,代码会回调LeScanCallback接口
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { runOnUiThread(new Runnable() { @Override public void run() { //device.getName();获取蓝牙设备名字 //device.getAddress();获取蓝牙设备mac地址 可以将数据使用EventBus进行需要传递 } }); } };3.6:搜索到设备的时候开始进行连接 - 代码里面进行服务的开启,里面进行读写的操作的封装
public boolean connect(final String address) {if (mBluetoothAdapter == null || address == null) {Log.w(TAG,"BluetoothAdapter not initialized or unspecified address.");return false;}// Previously connected device. Try to reconnect. (先前连接的设备。 尝试重新连接)if (mBluetoothDeviceAddress != null&& address.equals(mBluetoothDeviceAddress)&& mBluetoothGatt != null) {Log.d(TAG,"Trying to use an existing mBluetoothGatt for connection.");if (mBluetoothGatt.connect()) {mConnectionState = STATE_CONNECTING;return true;} else {return false;}}final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);if (device == null) {Log.w(TAG, "Device not found. Unable to connect.");return false;}// We want to directly connect to the device, so we are setting the// autoConnect// parameter to false.mBluetoothGatt = device.connectGatt(this, false, mGattCallback); //这里才是真正连接Log.d(TAG, "Trying to create a new connection.");mBluetoothDeviceAddress = address;mConnectionState = STATE_CONNECTING;return true;}3.7:当连接成功之后,会走BluetoothGatttCallBack接口,这里主要实现读写的操作
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {@Override //当连接上设备或者失去连接时会回调该函数public void onConnectionStateChange(BluetoothGatt gatt, int status,int newState) {if (newState == BluetoothProfile.STATE_CONNECTED) { //连接成功 mBluetoothGatt.discoverServices(); //连接成功后就去找出该设备中的服务 private BluetoothGatt mBluetoothGatt;} else if (newState == BluetoothProfile.STATE_DISCONNECTED) { //连接失败}}@Override //当设备是否找到服务时,会回调该函数public void onServicesDiscovered(BluetoothGatt gatt, int status) {if (status == BluetoothGatt.GATT_SUCCESS) { //找到服务了//在这里可以对服务进行解析,寻找到你需要的服务} else {Log.w(TAG, "onServicesDiscovered received: " + status);}}@Override //当读取设备时会回调该函数public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) {System.out.println("onCharacteristicRead");if (status == BluetoothGatt.GATT_SUCCESS) { //读取到的数据存在characteristic当中,可以通过characteristic.getValue();函数取出。然后再进行解析操作。 //int charaProp = characteristic.getProperties();if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0)表示可发出通知。 判断该Characteristic属性}}@Override //当向设备Descriptor中写数据时,会回调该函数public void onDescriptorWrite(BluetoothGatt gatt,BluetoothGattDescriptor descriptor, int status) {System.out.println("onDescriptorWriteonDescriptorWrite = " + status + ", descriptor =" + descriptor.getUuid().toString());}@Override //设备发出通知时会调用到该接口public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic) {if (characteristic.getValue() != null) { System.out.println(characteristic.getStringValue(0));}System.out.println("--------onCharacteristicChanged-----");}@Overridepublic void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {System.out.println("rssi = " + rssi);} @Override //当向Characteristic写数据时会回调该函数 public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) { System.out.println("--------write success----- status:" + status); };}
3.8:连接成功时候,我们可以获取板子中的服务 - 以及相关的服务的UUID(重要 - 后面图片实例介绍)public List<BluetoothGattService> getSupportedGattServices() {if (mBluetoothGatt == null)return null;return mBluetoothGatt.getServices(); //此处返回获取到的服务列表}3.9:获取到服务之后开始去解析服务 - 目的是为了将其中的uuid得到,因为后期的读写操作需要进行的使用Characteristic -
注意:这里你就可以和相关的嵌入式工程师交互,使用哪些服务以及使用哪些UUID即可
private void displayGattServices(List<BluetoothGattService> gattServices) {if (gattServices == null)return;for (BluetoothGattService gattService : gattServices) { // 遍历出gattServices里面的所有服务List<BluetoothGattCharacteristic> gattCharacteristics = gattServices.getCharacteristics();for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { // 遍历每条服务里的所有Characteristicif (gattCharacteristic.getUuid().toString().equalsIgnoreCase(需要通信的UUID)) { // 有哪些UUID,每个UUID有什么属性及作用,一般硬件工程师都会给相应的文档。我们程序也可以读取其属性判断其属性。// 此处可以可根据UUID的类型对设备进行读操作,写操作,设置notification等操作// BluetoothGattCharacteristic gattNoticCharacteristic 假设是可设置通知的Characteristic// BluetoothGattCharacteristic gattWriteCharacteristic 假设是可读的Characteristic// BluetoothGattCharacteristic gattReadCharacteristic 假设是可写的Characteristic}}}}4.0:当app发数据到串口的时候,可以在串口上面进行显示了,但是这里有一个坑就是串口发送数据到app这边的时候,收不到,没有反应,这时候你应该注意了,除了排查代码的原因外, 还要度娘一下最好。。。。。。深表其感!! 这里要设置一下可以接收通知Notifaction。
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {if (mBluetoothAdapter == null || mBluetoothGatt == null) {Log.w(TAG, "BluetoothAdapter not initialized");return;}mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));if (descriptor != null) {System.out.println("write descriptor");descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);mBluetoothGatt.writeDescriptor(descriptor);}}4.1:这个时候默认你知道了需要使用哪一个UUID了,呵呵!那就简单了, 可以进行读写的操作了 - - - 注意这里的读写操作都会进行3.7中的回调
public void readCharacteristic(BluetoothGattCharacteristic characteristic) { //可读的UUIDif (mBluetoothAdapter == null || mBluetoothGatt == null) {Log.w(TAG, "BluetoothAdapter not initialized");return;}mBluetoothGatt.readCharacteristic(characteristic);}
public void wirteCharacteristic(BluetoothGattCharacteristic characteristic) { //可写的UUIDif (mBluetoothAdapter == null || mBluetoothGatt == null) {Log.w(TAG, "BluetoothAdapter not initialized");return;}mBluetoothGatt.writeCharacteristic(characteristic);}4.2:这里的读写就要注意了(要根据项目的开发协议而定),一会儿实例!
4.3:针对读的操作在加深一下理解:请看
/***读操作***/ void readBatrery(){ //如上面所说,想要和一个学生通信,先知道他的班级(ServiceUUID)和学号(CharacUUID)//此处的0000180f...是举例,实际开发需要询问硬件那边BluetoothGattService batteryService=mBluetoothGatt.getService(UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb")); if(batteryService!=null){//此处的00002a19...是举例,实际开发需要询问硬件那边BluetoothGattCharacteristic batteryCharacteristic=batteryService.getCharacteristic(UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb")); if(batteryCharacteristic!=null){//读取电量, 这是读取batteryCharacteristic值的方法,读取其他的值也是如此,只是它们的ServiceUUID 和CharacUUID不一样mBluetoothGatt.readCharacteristic(batteryCharacteristic); } } }//如果读取电量(或者读取其他值)成功之后 ,会来到 回调: @Override public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); //读取到值,根据UUID来判断读到的是什么值 if (characteristic.getUuid().toString() .equals("00002a19-0000-1000-8000-00805f9b34fb")) {// 获取到电量 int battery = characteristic.getValue()[0]; } } /***写操作***/ void sendSetting(){//此处的00001805...是举例,实际开发需要询问硬件那边BluetoothGattService sendService=mBluetoothGatt.getService(UUID.fromString("00001805-0000-1000-8000-00805f9b34fb")); if(sendService!=null){//此处的00002a08...是举例,实际开发需要询问硬件那边BluetoothGattCharacteristic sendCharacteristic=sendService.getCharacteristic(UUID.fromString("00002a08-0000-1000-8000-00805f9b34fb")); if(sendCharacteristic!=null){ sendCharacteristic.setValue(new byte[] { 0x01,0x20,0x03 });//随便举个数据 mBluetoothGatt.writeCharacteristic(sendCharacteristic);//写命令到设备, } } } //如果下发配置成功之后,会来到回调: @Override public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); if (status == BluetoothGatt.GATT_SUCCESS) {//write成功(发送值成功),可以根据 characteristic.getValue()来判断是哪个值发送成功了,比如 连接上设备之后你有一大串命令需要下发,你调用多次写命令,
这样你需要判断是不是所有命令都成功了,因为android不太稳定,有必要来check命令是否成功,否则你会发现你明明调用 写命令,但是设备那边不响应 } }第四步:主要的相关的代码如上,具体的实现就没有直接展示了。敬请原谅!谢谢!
本人也是第一次操作蓝牙这一块,期间看了很多的博客,很有帮助,推荐给大家(链接),也可以自己去查资料。
点击打开链接
MODBUS协议 一种问答方式的通信协议
点击打开链接
Android BLE开发之Android手机与BLE终端通信
串口:使用的demo,app和蓝牙交互与串口交互:(有需要可以找我接收)
0 3
- Android Ble 4.0 蓝牙开发交互
- Android蓝牙4.0Ble开发
- Android Ble蓝牙开发
- android BLE蓝牙开发
- android 蓝牙BLE 开发
- Android:BLE蓝牙开发
- android ble蓝牙开发
- Android开发蓝牙4.0BLE开发
- android ble蓝牙开发略解-Android 蓝牙4.0开发
- android ble 蓝牙4.0开发-rssi
- android ble 蓝牙4.0 cc2540 开发(一)
- android ble 蓝牙4.0开发日志
- 浅谈android蓝牙4.0BLE开发
- Android BLE蓝牙4.0开发详解
- Android 蓝牙4.0(ble)开发的解决方案
- Android BLE蓝牙4.0开发详解
- Android蓝牙4.0 BLE开发坑总结
- Android 蓝牙4.0 BLE 开发总结
- linux指令wc/pgrep
- spring mvc 注解事务不生效
- sequel pro 连接mysql数据库遇到的问题
- spring常用注解辨析
- Java多线程系列--“基础篇”02之 常用的实现多线程的两种方式
- Android Ble 4.0 蓝牙开发交互
- ArrayList、Vector、HashMap、HashSet的默认初始容量、加载因子、扩容增量
- Java常见的几种排序算法-插入、选择、冒泡、快排、堆排等
- 一颗二叉查找树的简单实现
- c++智能指针(1)
- 微信小程序入门之构建一个简单TODOS应用
- 系统自检-FLASH自检
- PAT 1042. Shuffling Machine (20)
- 108-记录锁(继承与释放)