刚刚做了一个关于BLE蓝牙通信的Android应,现在回头看看这个过程,想把这些代码分享给那些需要的同学,由于第一次写,很多地方不懂,写的不好,多多包涵。

       开始正题,关于BLE蓝牙,有不少博客详细介绍了,在关联的URL处添加了一些可以参考,个人觉得最重要的一部分是关于其UUID部分,service和characteristic都有一个唯一的UUID来识别,我们需要知道蓝牙模块发送数据对应的UUID值,而接收或者发送的数据通过characteristic实现,不同的characteristic具有不同的属性(可读,可写,通知),而我们的characteristic包含在service里,即我们需要知道service和characteristic对应的UUID。

BLE_SERVICE和BLE_SERVICE_READ,其他的UUID包括一些产品信息,以及配置的UUID。

1.BleDefinedUUIDs.java文件

class BleDefinedUUIDs {
    //Service对应的UUID
    static class Service {
        final static UUID BLE_SERVICE=UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb");
    };

    static class Characteristic {
        //characteristic的UUID
//        final static public UUID HEART_RATE_MEASUREMENT   = UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb");
        final static UUID BLE_SERVICE_READ           = UUID.fromString("0000fff4-0000-1000-8000-00805f9b34fb");
        final static public UUID MANUFACTURER_STRING      = UUID.fromString("00002a29-0000-1000-8000-00805f9b34fb");
        final static public UUID MODEL_NUMBER_STRING      = UUID.fromString("00002a24-0000-1000-8000-00805f9b34fb");
        final static public UUID FIRMWARE_REVISION_STRING = UUID.fromString("00002a26-0000-1000-8000-00805f9b34fb");
        final static public UUID APPEARANCE               = UUID.fromString("00002a01-0000-1000-8000-00805f9b34fb");
        final static public UUID BODY_SENSOR_LOCATION     = UUID.fromString("00002a38-0000-1000-8000-00805f9b34fb");
    }

    static class Descriptor {
        final static UUID CHAR_CLIENT_CONFIG       = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
    }
}

2.MainActivity.java文件

2.1判断设备是否支持蓝牙以及连接蓝牙(BLE蓝牙不同于手机系统配置的蓝牙,不需要输入密码)

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
/**
         * 判断当前设备是否支持ble
         */
        if (!getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_BLUETOOTH_LE)) {
            System.out.println("不支持BLE设备");
        }
        //得到蓝牙适配器
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, REQUEST_ENABLE_BT);
        }
        Button start = (Button) findViewById(R.id.start);
        lv = (ListView) findViewById();
        final TextView state = (TextView) findViewById(R.id.state);
        adapter = new LeDeviceListAdapter();
        start.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                scanLeDevice(true);
                lv.setAdapter(adapter);
                adapter.clear();
            }

        });
        lv.setOnItemClickListener(new OnItemClickListener() {

            private BluetoothGatt gatt;
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                                    int position, long id) {
                //把搜索到的设备信息放到listview中,然后连接设备
                BluetoothDevice device = adapter.getDevice(position);
                state.setText("已连接");
                gatt = device.connectGatt(getApplicationContext(), false,
                        mGattCallback);
            }
        });
    }

2.2获得对应的服务以及characteristic

@Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //                System.out.println("Services discovered");
                //得到数据信息的service
                BluetoothGattService service = gatt
                        .getService(BLE_SERVICE);
                if(service!=null){
                    mCharacteristic=service.getCharacteristic(BLE_SERVICE_READ);
                    boolean success=gatt.setCharacteristicNotification(mCharacteristic,true);
                    if (!success) {
                        Toast.makeText(MainActivity.this, "数据通知出错", Toast.LENGTH_LONG).show();
                    }
                    BluetoothGattDescriptor descriptor = mCharacteristic.getDescriptor(BleDefinedUUIDs.Descriptor.CHAR_CLIENT_CONFIG);
                    if (descriptor != null) {
                        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                        gatt.writeDescriptor(descriptor);
                    }
                }
            }
        }

2.3当characteristic的值发生变化时,能够及时获得变化后的值,接收到的数据根据对应的通信协议来实现数据转换。本次接收的为12位16进制数据,通过实验发现其中包含的电压单位信息以及万用表显示的数据信息,通过将接收到的数据变为字符串,对字符串的截取处理十分方便,然后获得其变为float型以实现数据的真实数值。

/**
         * 当service里边的characteristic发生改变调用
         */
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                                             BluetoothGattCharacteristic characteristic) {
            if(characteristic.equals(mCharacteristic))
            {
                final byte[] raw = mCharacteristic.getValue();
                final String data=bytesToHexString(raw);
                final int sign=Integer.parseInt(data.substring(10,11));//判断符号位是否为负,若为负则将其设为0
                final int dot = Integer.parseInt(data.substring(1, 2));
                final int unit=Integer.parseInt(data.substring(0,1));
                runOnUiThread(new Runnable() {
                    @Override
                   public void run() {
                        //决定单位为V还是mV
                        switch(unit){
                            case 1:
                                TextView textView=(TextView)findViewById(R.id.unit);
                                textView.setText("mV");break;
                            case 2:
                                TextView textView_1=(TextView)findViewById(R.id.unit);
                                textView_1.setText("V");break;
                            default: Toast.makeText(MainActivity.this,"暂没开放此档位相关功能",Toast.LENGTH_SHORT).show();break;
                    }

                    //数据显示
                    if(sign<8) {
                        if(dot==3|dot==2|dot==1){
                            int dotDecision= (int) Math.pow(10,dot);//根据记录以及数据格式类型发现,当dot该位置为1,2,3时,
                            // 其小数点分别位于右2,3,4位,顾考虑将其除以对应的dot次方,格式网站(https://note.youdao.com/share/?token=517D506A7CF04DB3A2406129928B0B08&gid=15157487#/)
                            float a=((float)Integer.parseInt(data.substring(10, 12) + data.substring(8, 10), 16))/dotDecision;//将字符串连接转换为float类型
                            String display=a+"";//将float转换为字符串,以显示
                            TextView textView = (TextView) findViewById();
                            textView.setText(display);
                        }else if(dot==9){
                            float a=((float)Integer.parseInt(data.substring(10, 12) + data.substring(8, 10), 16))/10;//将字符串连接转换为float类型
                            String display=a+"";//将float转换为字符串,以显示
                            TextView textView = (TextView) findViewById();
                            textView.setText(display);
                        }
//                        else {
//                            Toast.makeText(MainActivity.this,"请确认万用表在V档位",Toast.LENGTH_LONG).show();
//                        }
                       }else {
                           String display=""+0;//考虑到暂时用不到负数,故将其设置为0处理
                             TextView textView = (TextView) findViewById();
                             textView.setText(display);
                           Toast.makeText(MainActivity.this,"请检查万用表是否接反而造成负值",Toast.LENGTH_SHORT).show();
                        }
//                  Toast.makeText(MainActivity.this, data, Toast.LENGTH_LONG).show();
                      }
                    });
                 }else {
                Toast.makeText(MainActivity.this, "无数据", Toast.LENGTH_LONG).show();
            }
        }
        //将byte类型转换为字符串类型
        public String bytesToHexString(byte[] raw){
            StringBuilder stringBuilder = new StringBuilder("");
            if (raw == null || raw.length <= 0) {
                return null;
            }
            for (int i = 0; i < raw.length; i++) {
                int v = raw[i] & 0xFF;
                String hv = Integer.toHexString(v);
                if (hv.length() < 2) {
                    stringBuilder.append(0);
                }
                stringBuilder.append(hv);
            }
            return stringBuilder.toString();
        }

3.总结

Android 蓝牙发送接收指令 android接收蓝牙数据_Android

上图为手机界面,由于本次只是接收蓝牙传输数据加以显示,下一步将依据接收到的数据设置阈值以控制其他设备