android ble 蓝牙4.0多机通讯客户端实现
来源:互联网 发布:oracle数据库试题 编辑:程序博客网 时间:2024/06/02 04:04
自从进入软件开发行业,都是一直在CSDN上索取无数资料,一直没有贡献过,今天突然想写点什么,第一次写,写点简单的吧,不知道有没有人看。
蓝牙从4.0开始,支持了多设备通讯,android 4.3开始支持了蓝牙4.0,即 android ble关于ble 网上资料很多,也讲的很详细。只要对官方例子简单的改造就可以实现多机通讯了。
要理解蓝牙多机通讯,其实把他和网络通讯类比就知道了,在网络通讯中,需要一台设备作为服务器,开启了监听,其他电脑才能连接上。在ble中其实就是这样的,一台先创
建服务并监听,另一台扫描并建立连接。把BluetoothGatt当做socket就可以了,因此蓝牙多机通讯其实就是一台蓝牙客户端连接多台蓝牙服务器,蓝牙客户端需要创建多个
BluetoothGatt来一一匹配每个服务端。对于android手机蓝牙服务端编程需要涉及到:BLEPeripheral(android5.0以上才支持),这个网上也是有现成的demo的。
服务端代码如下:
创建了一个数据服务(并支持读和写),有服务端才好讲客户端,还是一句话,把ble当做是网络socket通讯就对了,只不过ble服务端只能支持一个连接。
在这里没有进行数据处理。需要自己实现
@SuppressLint("NewApi")public class BLEPeripheral { Context context; BluetoothManager mManager; BluetoothAdapter mAdapter; BluetoothLeAdvertiser mLeAdvertiser; BluetoothGattServer mGattServer; public static boolean isEnableBluetooth(){ return BluetoothAdapter.getDefaultAdapter().isEnabled(); } public BLEPeripheral(Context context){ this.context=context; }@SuppressLint("NewApi")public int init(){ if(null == mManager) mManager = (BluetoothManager)context.getSystemService(Context.BLUETOOTH_SERVICE); if(null == mManager) return -1; if(false == context.getPackageManager(). hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) return -2; if(null == mAdapter) mAdapter = mManager.getAdapter(); if(false == mAdapter.isMultipleAdvertisementSupported()) return -3; return 0; } public void close() { } public static String getAddress(){ return BluetoothAdapter.getDefaultAdapter().getAddress(); } @SuppressLint("NewApi") private AdvertiseCallback mAdvCallback = new AdvertiseCallback() { @Override public void onStartFailure(int errorCode){ Log.d("advertise","onStartFailure"); } @Override public void onStartSuccess(AdvertiseSettings settingsInEffect){ Log.d("advertise","onStartSuccess"); }; }; @SuppressLint("NewApi") private final BluetoothGattServerCallback mGattServerCallback= new BluetoothGattServerCallback(){ @SuppressLint("NewApi")@Override public void onConnectionStateChange(BluetoothDevice device, int status, int newState){ Log.d("GattServer", "Our gatt server connection state changed, new state "); Log.d("GattServer", Integer.toString(newState)); super.onConnectionStateChange(device, status, newState); } @SuppressLint("NewApi")@Override public void onServiceAdded(int status, BluetoothGattService service) { Log.d("GattServer", "Our gatt server service was added."); super.onServiceAdded(status, service); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)@SuppressLint("NewApi")@Override public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { Log.d("GattServer", "Our gatt characteristic was read."); super.onCharacteristicReadRequest(device, requestId, offset, characteristic); mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue()); } @SuppressLint("NewApi")@Override public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { Log.d("GattServer", "We have received a write request for one of our hosted characteristics"); Log.d("GattServer", "data = "+ value.toString()); super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value); } @Override public void onNotificationSent(BluetoothDevice device, int status) { Log.d("GattServer", "onNotificationSent"); super.onNotificationSent(device, status); } @Override public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) { Log.d("GattServer", "Our gatt server descriptor was read."); super.onDescriptorReadRequest(device, requestId, offset, descriptor); } @Override public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { Log.d("GattServer", "Our gatt server descriptor was written."); super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value); } @Override public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) { Log.d("GattServer", "Our gatt server on execute write."); super.onExecuteWrite(device, requestId, execute); } }; public void startAdvertise() { if(null == mAdapter) return; if (null == mLeAdvertiser) mLeAdvertiser = mAdapter.getBluetoothLeAdvertiser(); if(null == mLeAdvertiser) return; AdvertiseSettings.Builder settingBuilder; settingBuilder = new AdvertiseSettings.Builder(); settingBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY); settingBuilder.setConnectable(true); settingBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH); AdvertiseData.Builder advBuilder; advBuilder = new AdvertiseData.Builder(); mAdapter.setName("HUD"); //8 characters works, 9+ fails advBuilder.setIncludeDeviceName(true); mGattServer = mManager.openGattServer(context, mGattServerCallback); // addDeviceInfoService(mGattServer); final String DATA_SERVICE = "<span style="font-family: Arial, Helvetica, sans-serif;">00003a06-0000-1000-8000-00805f9b34fb</span>"; final String READ = "<span style="font-family: Arial, Helvetica, sans-serif;">00002a09-0000-1000-8000-00805f9b34fb</span>"; final String WRITE = "<span style="font-family: Arial, Helvetica, sans-serif;">00002a05-0000-1000-8000-00805f9b34fb</span>"; BluetoothGattCharacteristic read2Characteristic = new BluetoothGattCharacteristic( UUID.fromString(READ), BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ ); // read2Characteristic.setValue(new String("this is read 2").getBytes()); BluetoothGattCharacteristic writeCharacteristic = new BluetoothGattCharacteristic( UUID.fromString(WRITE), BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE ); BluetoothGattService AService = new BluetoothGattService( UUID.fromString(DATA_SERVICE), BluetoothGattService.SERVICE_TYPE_PRIMARY); AService.addCharacteristic(read2Characteristic); AService.addCharacteristic(writeCharacteristic); // Add notify characteristic here !!! mGattServer.addService(AService); mLeAdvertiser.startAdvertising(settingBuilder.build(), advBuilder.build(), mAdvCallback); } public void stopAdvertise() { if(null != mLeAdvertiser) mLeAdvertiser.stopAdvertising(mAdvCallback); mLeAdvertiser = null; }}
对于客户端:
打开蓝牙扫描蓝牙就不讲了,主要讲一下BluetoothGatt:
对于ble 客户端来说一个连接就是一个BluetoothGatt通道,要实现多机通讯,客户端要时实现多个BluetoothGatt,并实现多个BluetoothGattCallback。
连接并创建通道:mBluetoothGatt = device.connectGatt(context, false,BluetoothGattCallback);
其中device 就是扫描到的 BluetoothDevice device,这里需要实现BluetoothGattCallback接口 并选择性的实现里面的方法:
BluetoothGattCallback 中的方法1:onConnectionStateChange,蓝牙连接和丢失状态回调,在这里就可以进行服务扫描操作。
BluetoothGattCallback 中的方法2:onServicesDiscovered扫描到服务后回调,扫描到服务后通过通过UUID提取服务(需要和服务端注册的UUID一致),并设置数据接收方式等。
这里附上我实现的一个通用方法,在里面实现连接,数据发送,数据接收等一系列操作,
只要创建一个BtGattCallback 的实例就可以实现通讯了,当然多机通讯就是实现多个实例就OK了
我用一个Tag字符串来唯一标示一个连接,当创建多个连接的,可以通过不同的Tag 来区分不同的连接,只要自己事先定义好
@SuppressLint("NewApi")public class BtGattCallback extends BluetoothGattCallback {private BluetoothGatt mBluetoothGatt;Context context;String Tag;String Addr="";public static boolean isread=false; BluetoothGattCharacteristic writeCharacteristic; BluetoothGatt blueToothGatt; MessageGetInterface messageGet; BluetoothAdapter mBluetoothAdapter; public String getTag(){ return Tag; } public String getAddr(){ return Addr; } public void discoverServices(){ if(mBluetoothGatt!=null) mBluetoothGatt.discoverServices(); } public boolean SendMessage(byte[] msg){ isread=false; if(blueToothGatt!=null){ writeCharacteristic.setValue(msg); if(blueToothGatt.writeCharacteristic(writeCharacteristic)){ return true; } } return false; } /** * Connects to the GATT server hosted on the Bluetooth LE device. * * @param address The device address of the destination device. * * @return Return true if the connection is initiated successfully. The connection result * is reported asynchronously through the * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * callback. */ public boolean connect(final String address) { if (mBluetoothAdapter == null || address == null) { return false; } Addr=address; final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); if (device == null) { return false; } // We want to directly connect to the device, so we are setting the autoConnect // parameter to false. mBluetoothGatt = device.connectGatt(context, false,this); return true; } /** * Disconnects an existing connection or cancel a pending connection. The disconnection result * is reported asynchronously through the * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} * callback. */ public void disconnect() { if (mBluetoothAdapter == null || mBluetoothGatt == null) { return; } if(mBluetoothGatt!=null) mBluetoothGatt.disconnect(); } /** * After using a given BLE device, the app must call this method to ensure resources are * released properly. */ public void close() { if (mBluetoothGatt == null) { return; } mBluetoothGatt.close(); mBluetoothGatt = null; }public BtGattCallback(Context context,String tag,MessageGetInterface messageGet,BluetoothAdapter mBluetoothAdapter){this.mBluetoothAdapter=mBluetoothAdapter;this.messageGet=messageGet;this.context=context;Tag=tag;} private void broadcastUpdate(final String action) { final Intent intent = new Intent(action); intent.putExtra("tag", Tag); context.sendBroadcast(intent); } @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { if (newState == BluetoothProfile.STATE_CONNECTED) { mBluetoothGatt.discoverServices(); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { broadcastUpdate(BluetoothLeService.ACTION_GATT_DISCONNECTED); } } @Override public void onServicesDiscovered(final BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { BluetoothGattService gattService = gatt.getService(UUID.fromString(SampleGattAttributes.Data_Service)); if (gattService != null) { writeCharacteristic = gattService.getCharacteristic(UUID.fromString(SampleGattAttributes.sendData_Characteristic)); blueToothGatt=gatt; BluetoothGattCharacteristic notifyCharacteristic = gattService.getCharacteristic(UUID.fromString(SampleGattAttributes.getData_Characteristic)); BluetoothGattDescriptor descriptor = notifyCharacteristic.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); if(notifyCharacteristic != null && descriptor != null){ descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); gatt.setCharacteristicNotification(notifyCharacteristic, true); gatt.writeDescriptor(descriptor); broadcastUpdate(BluetoothLeService.ACTION_GATT_CONNECTED); return; } } } broadcastUpdate(BluetoothLeService.ACTION_GATT_DISCONNECTED); } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { messageGet.Read(characteristic.getValue(), Tag); } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { messageGet.Read(characteristic.getValue(), Tag); }}
public interface MessageGetInterface {public void Read(byte[] msg,String tag);}
public class SampleGattAttributes { private static HashMap<String, String> attributes = new HashMap<String, String>(); public static String sendData_Characteristic = "00002a09-0000-1000-8000-00805f9b34fb"; public static String getData_Characteristic = "00002a05-0000-1000-8000-00805f9b34fb"; public static String Data_Service ="00003a06-0000-1000-8000-00805f9b34fb"; static { // Sample Services. //attributes.put(sendData_Service, "Send Data Service"); attributes.put(Data_Service, "Data Service"); // Sample Characteristics. attributes.put(sendData_Characteristic, "发送"); attributes.put(getData_Characteristic, "接收");// attributes.put(HEART_RATE_MEASUREMENT, "Heart Rate Measurement"); } public static String lookup(String uuid, String defaultName) { String name = attributes.get(uuid); return name == null ? defaultName : name; }}
可以把服务端跑在多个手机上,然后在一个手机上同时连接多个手机,具体扫描呀,之类的在这里省略了。
我连接的不是手机服务端,而是可穿戴设备,就是一个手机连接多个可穿戴设备。对客户端来说实现都是一样的。
- android ble 蓝牙4.0多机通讯客户端实现
- Android BLE蓝牙通讯学习
- Android 蓝牙4.0 Ble通讯问题小汇总
- Android蓝牙4.0BLE通讯读写数据更新
- Android BLE低功耗蓝牙开发(下) BLE客户端(中央设备)与GATT服务的通讯
- Android蓝牙4.0BLE
- Android ble 蓝牙4.0
- Android BLE蓝牙4.0
- android ble : 一(蓝牙门禁的ble通讯完整流程)
- Android Ble蓝牙开发(客户端)
- Android 蓝牙4.0 Ble 连接Ble模块
- Android 蓝牙4.0 BLE调试
- Android 蓝牙4.0 BLE调试
- Android 蓝牙4.0 BLE 理解
- Android ble 蓝牙4.0 总结
- Android 蓝牙4.0 BLE 理解
- Android 蓝牙4.0 BLE 理解
- Android 蓝牙4.0 BLE 理解
- Nginx学习笔记七Nginx的Web缓存服务
- 类和对象
- delphi中Tlist的使用。
- 【6-6】HBASE的Java接口(2)
- 电脑基础知识:BIOS的含义及功能简介
- android ble 蓝牙4.0多机通讯客户端实现
- 绘制Objective-C程序的UML类图
- 本地推送及远程推送
- 后缀数组模板
- iOS-UI-基本控件之UIButton
- RFID+二维码扫描
- Unity3D Shader官方教程翻译(一)
- JDK5News
- 有一个桶,里面有白球、黑球各100个,人们必须按照以下的规则把球取出来: