在一家偏硬件的一家公司从事穿戴式设备的开发,通过近几个月学习与研究对于蓝牙4.0的通讯还有有点自己的见解,有不足的地方大家可以一起讨论,互相学习,废话不多说,那么如何进行蓝牙4.0的通讯与数据传输呢?本demo比较简单,大家应该都可以很好理解与学习的!
有基本的几个步骤,下面是一些代码段,希望对大家有所帮助吧。
添加蓝牙权限,
<uses-permission android:name="android.permission.BLUETOOTH"/><uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/><uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>判断手机手机是否支持蓝牙ble// 检查当前手机是否支持ble 蓝牙,如果不支持退出程序if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, "设备不支持BLE 蓝牙", Toast.LENGTH_SHORT).show(); finish();}//获得蓝牙适配器对象BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();对于蓝牙的搜索过程采用广播:/** 因为蓝牙在搜索到设备和搜索完毕都是通过广播发送的,这里我们需要注册广播接收器 */IntentFilter intentFilter = new IntentFilter( BluetoothDevice.ACTION_FOUND);registerReceiver(receiver, intentFilter);intentFilter = new IntentFilter( BluetoothAdapter.ACTION_DISCOVERY_FINISHED);registerReceiver(receiver, intentFilter);//注册蓝牙信号强度intentFilter = new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED);registerReceiver(receiver, intentFilter);广播的注册://注册广播 PRivate final BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context arg0, Intent intent) { String action = intent.getAction(); // 判断这个广播是否是蓝牙搜索到设备的广播 if (action.equals(BluetoothDevice.ACTION_FOUND)) { // 获取到传递过来的设备信息 BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device.getBondState() != BluetoothDevice.BOND_BONDED) { //信号强度 short rssi = intent.getExtras().getShort( BluetoothDevice.EXTRA_RSSI); String s = String.valueOf(rssi); mDeviceList.add(device.getName() + "/n" + device.getAddress() + "/n" + "信号强度:" + s +"dbm"); arrayAdapter.notifyDataSetChanged(); } // 判断是否为搜索完毕的广播 } else if (action .equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) { /***/// setTitle("连接蓝牙设备"); bt_search.setText("搜索完毕"); } } };项目创建时需要打开蓝牙,详细代码片段// 为了确保设备上蓝牙能使用, 如果当前蓝牙设备没启用,弹出对话框向用户要求授予权限来启用if (!mBluetoothAdapter.isEnabled()) { Intent enabletIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enabletIntent, REQUEST_CODE);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_CANCELED) { finish(); return; }}基本工作有了这些后,我们建立一个listview来显示搜索到的蓝牙设备,//适配器 + Listview显示arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,mDeviceList);listView.setAdapter(arrayAdapter);2.如何进行扫描呢?这里采用的是按钮触发:bt_search.setText("正在搜索蓝牙设备...");if(mBluetoothAdapter.isDiscovering()){ mBluetoothAdapter.cancelDiscovery();}mBluetoothAdapter.startDiscovery();其实这个时候点击按钮,并没有任何显示,因为我们得用一个集合加载搜索到的设备,前面采用MVC的模式进行适配,将搜索到的设备加载到链表里面//数据源存放蓝牙设备----------------获取已绑定的设备,将其存放于set集合Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices();if(devices.size() > 0){ for (BluetoothDevice device:devices) { mDeviceList.add(device.getName() + "/n" + device.getAddress()); }}将搜索到的设备显示到listview上后对其item项进行进一步的连接,并进行通信、因为要连接设备的地址,这里进行字符串的截取String s = mDeviceList.get(position); String a[] = s.split("/n"); String name = a[0]; String address = a[1]; Log.i(TAG, "address =" + address); if (mBluetoothAdapter == null || address == null) { Log.w(TAG, "蓝牙适配器为空或者地址为空."); return; } //根据地址取得设备 device = mBluetoothAdapter.getRemoteDevice(address); //获取链接 这个时候需要实现BluetoothGattCallback bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback);接下来执行回调方法,回调方法主要有onConnectionStateChange, // 返回链接状态onServicesDiscovered, //发现服务时调用此方法onCharacteristicRead //字段读onCharacteristicWrite //字段写onCharacteristicChanged //蓝牙通信内容写入写出时调用此方法onDescriptorRead // 字段读onDescriptorWrite //字段写//回调方法 private BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() { // 返回链接状态 @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); Log.i(TAG,"onConnectionStateChange"); if (newState == BluetoothProfile.STATE_CONNECTED) { //连接成功 因为是异步调用的 所以刷新UI的操作要放在主线程中,当然也可以使用hanlder Eventbus等 随便 runOnUiThread(new Runnable() { @Override public void run() { link = 1; tv_address.setText("连接成功" + device.getAddress()); } }); //发现服务,连接成功 gatt.discoverServices(); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { //断开连接 link = 2; runOnUiThread(new Runnable() { @Override public void run() { tv_address.setText("连接断开"); } }); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); Log.i(TAG,"onServicesDiscovered"); if (status == BluetoothGatt.GATT_SUCCESS) { bluetoothGattServiceList = bluetoothGatt.getServices(); for (int i = 0; i < bluetoothGattServiceList.size(); i++) { BluetoothGattService bluetoothGattService = bluetoothGattServiceList .get(i); if (bluetoothGattService.getUuid().equals(BleConstants.TEMP_SERVICE_UUID)) { BleConstants.type = 1; break; } else if (bluetoothGattService.getUuid().equals(BleConstants.TEMP_SERVICE_UUID_G)) { BleConstants.type = 0; break; } } //------------------------- for (int i = 0; i < bluetoothGattServiceList.size(); i++) { BluetoothGattService bluetoothGattService = bluetoothGattServiceList .get(i); Log.i(TAG,"Service UUID-" + i + ":" + bluetoothGattService.getUuid()); List<BluetoothGattCharacteristic> bluetoothGattCharacteristicList = bluetoothGattService .getCharacteristics(); for (int j = 0; j < bluetoothGattCharacteristicList.size(); j++) { BluetoothGattCharacteristic bluetoothGattCharacteristic = bluetoothGattCharacteristicList .get(j); Log.i(TAG,"Characteristic UUID-" + i + "-" + j + ":" + bluetoothGattCharacteristic.getUuid()); if (bluetoothGattCharacteristic.getUuid().equals(BleConstants.TEMP_CHAR_UUID)) { Log.i(TAG, "TEMP_CHAR_UUID"); } else if (bluetoothGattCharacteristic.getUuid().equals(BleConstants.TEMP_BATTERY_CHAR_UUID)) { Log.i(TAG, "BATTERY_CHAR_UUID" + bluetoothGattCharacteristic.getUuid().toString()); } else if (bluetoothGattCharacteristic.getUuid() .equals(BleConstants.TEMP_UART_WRITE_CHAR_UUID)) { } else if (bluetoothGattCharacteristic.getUuid() .equals(BleConstants.TEMP_UART_READ_CHAR_UUID)) { } } } read(); Log.i(TAG, "BluetoothGatt.GATT_SUCCESS"); } } @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicRead(gatt, characteristic, status); Log.i(TAG,"onCharacteristicRead"); } /** * write成功(发送值成功) 写入Characteristic成功与否的回调 可以根据 * characteristic.getValue()来判断是哪个值发送成功了,比如 连接上设备之后你有一大串命令需要下发,你调用多次写命令, * 这样你需要判断是不是所有命令都成功了,因为android不太稳定,有必要来check命令是否成功,否则你会发现你明明调用 * 写命令,但是设备那边不响应 */ @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); Log.i(TAG,"onCharacteristicWrite"); } @Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); Log.i(TAG,"onCharacteristicChanged"); byte[] read_data = characteristic.getValue(); String as = byteToHexString(read_data); Log.i(TAG, "as = " + as); float abcd = 0; if(read_data[1] == 0x01){ //温度 abcd = (float) ((read_data[2]) * 256 + (0x000000FF & read_data[3])) / 10; } string1 = String.valueOf(abcd); Log.i(TAG, "string1 =" + string1); } @Override public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorRead(gatt, descriptor, status); Log.i(TAG,"onDescriptorRead"); } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorWrite(gatt, descriptor, status); Log.i(TAG,"onDescriptorWrite"); } };read()方法如下:public void read() { if (BleConstants.type == 1) { BluetoothGattService bluetoothGattServic = bluetoothGatt .getService(BleConstants.TEMP_UART_SERVICE_UUID); BluetoothGattCharacteristic bluetoothGattCharacteristic = bluetoothGattServic .getCharacteristic(BleConstants.TEMP_UART_READ_CHAR_UUID); for (int k = 0; k < bluetoothGattCharacteristic.getDescriptors().size(); k++) { BluetoothGattDescriptor descriptor = bluetoothGattCharacteristic .getDescriptors().get(k); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); bluetoothGatt.writeDescriptor(descriptor); } //发送通知 bluetoothGatt.setCharacteristicNotification( bluetoothGattCharacteristic, true); } else if (BleConstants.type == 0) { BluetoothGattService bluetoothGattServic = bluetoothGatt .getService(BleConstants.TEMP_SERVICE_UUID_G); BluetoothGattCharacteristic bluetoothGattCharacteristic = bluetoothGattServic .getCharacteristic(BleConstants.TEMP_READ_CHAR_UUID_G); for (int k = 0; k < bluetoothGattCharacteristic.getDescriptors().size(); k++) { BluetoothGattDescriptor descriptor = bluetoothGattCharacteristic.getDescriptors().get(k); //ENABLE_NOTIFICATION_VALUE descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); bluetoothGatt.writeDescriptor(descriptor); } bluetoothGatt.setCharacteristicNotification( bluetoothGattCharacteristic, true); }}进制转换的方法:public String byteToHexString(byte[] bArray) { StringBuffer sb = new StringBuffer(bArray.length); Log.i(TAG, "bArray.length = " + bArray.length); //长度为5 String sTemp; for (int i = 0; i < bArray.length; i++) { Log.i(TAG, "bArray = " + bArray[i]); // 5, 1, 0, -2, -6 //将整数变为字符串 // 0xff是十六进制FF的表示方法,因为一个十六进制数字转换成二进制是四位,即F=1111, // 所以0xff占用一个字节 。也就是说是1B,1KB是1024B。 //另外你表达不太清楚,如果你问FF KB是多少,十六进制FF=15*16+15*1=255,即255KB sTemp = Integer.toHexString(0xFF & bArray[i]);// Log.i(TAG, "sTemp" + sTemp); //Log: sTemp 5, sTemp 1, sTemp 0, sTemp fc, sTemp f8 ---as: 05 01 00F6 F2 if (sTemp.length() < 2) sb.append(0); sb.append(sTemp.toUpperCase()); } return sb.toString(); }蓝牙通信需要用到的UUID,关于uuid不懂的就自己百度了。
// 温度值蓝牙特征服务UUIDpublic static final UUID TEMP_SERVICE_UUID = UUID.fromString("00001809-0000-1000-8000-00805f9b34fb");// 温度值蓝牙特征值UUIDpublic static final UUID TEMP_CHAR_UUID = UUID.fromString("00002A1C-0000-1000-8000-00805f9b34fb");那为了保证数据传输并显示,这里主要测试了温度的显示。
// handler类接收数据 Handler handler = new Handler() { public void handleMessage(Message msg) { if (msg.what == 1) { tv_display.setText(string1 + "℃"); } }; }; // 线程类 class ThreadShow implements Runnable { @Override public void run() { while (true) { try { Thread.sleep(300); Message msg = new Message(); msg.what = 1; handler.sendMessage(msg); } catch (Exception e) { e.printStackTrace(); } } } }以上就是关于蓝牙如何连接以及通信数据的自己的一点学习经验,目前还在深圳找工作,期待找到一家适合自己的工作吧!
新闻热点
疑难解答