Android 蓝牙4.0BLE开发实现对蓝牙的写入数据和读取数据

来源:互联网 发布:linux 域名绑定目录 编辑:程序博客网 时间:2024/05/17 16:43

Android 蓝牙4.0BLE开发实现对蓝牙的写入数据和读取数据


代码基本上都是官方的demo,只是通过修改获得自己想要的结果,下面就简单介绍一下自己的理解。

一、扫描BLE设备activity

检查该设备是否支持BLE设备,谷歌在Android4.3才开始支持BLE设备(晕死,很长一段时间都没有一台4.3的设备,看着程序修改了也不能测试!)。

 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {            Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();            finish();        }

初始化获得一个bluetoothManager,并检测设备是否支持蓝牙

final BluetoothManager bluetoothManager =                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);        mBluetoothAdapter = bluetoothManager.getAdapter();
// Checks if Bluetooth is supported on the device.        if (mBluetoothAdapter == null) {            Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();            finish();            return;        }
扫描BLE设备,然后添加到listView里面。

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);                    invalidateOptionsMenu();                }            }, SCAN_PERIOD);            mScanning = true;            mBluetoothAdapter.startLeScan(mLeScanCallback);        } else {            mScanning = false;            mBluetoothAdapter.stopLeScan(mLeScanCallback);        }        invalidateOptionsMenu();    }

二、蓝牙控制的服务BluetoothLeService

在这个服务里面有一个很重要的回调函数BluetoothGattCallback(),蓝牙的数据读取和状态改变都会回调这个函数。

private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {        @Override        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {            String intentAction;          //收到设备notify值 (设备上报值)            if (newState == BluetoothProfile.STATE_CONNECTED) {                intentAction = ACTION_GATT_CONNECTED;                mConnectionState = STATE_CONNECTED;                broadcastUpdate(intentAction);                Log.i(TAG, "Connected to GATT server.");                // Attempts to discover services after successful connection.                Log.i(TAG, "Attempting to start service discovery:" +                        mBluetoothGatt.discoverServices());            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {                intentAction = ACTION_GATT_DISCONNECTED;                mConnectionState = STATE_DISCONNECTED;                Log.i(TAG, "Disconnected from GATT server.");                broadcastUpdate(intentAction);            }        }        @Override        public void onServicesDiscovered(BluetoothGatt gatt, int status) {            if (status == BluetoothGatt.GATT_SUCCESS) {                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);            } else {                Log.w(TAG, "onServicesDiscovered received: " + status);                System.out.println("onServicesDiscovered received: " + status);            }        }        @Override        public void onCharacteristicRead(BluetoothGatt gatt,                                         BluetoothGattCharacteristic characteristic,                                         int status) {        //读取到值,在这里读数据            if (status == BluetoothGatt.GATT_SUCCESS) {                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);            }        }        @Override        public void onCharacteristicChanged(BluetoothGatt gatt,                                            BluetoothGattCharacteristic characteristic) {            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);        }    };
在官方的demo中还使用到广播,可能是因为人大神写的,要严谨些。我一开始看的时候就得这有点麻烦,跳转的多麻烦。

private void broadcastUpdate(final String action) {        final Intent intent = new Intent(action);        sendBroadcast(intent);    }    private void broadcastUpdate(final String action,                                 final BluetoothGattCharacteristic characteristic) {        final Intent intent = new Intent(action);        // This is special handling for the Heart Rate Measurement profile.  Data parsing is        // carried out as per profile specifications:        // http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml        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));            intent.putExtra(EXTRA_DATA, String.valueOf(heartRate));        } else {            // For all other profiles, writes the data formatted in HEX.对于所有的文件,写入十六进制格式的文件        //这里读取到数据            final byte[] data = characteristic.getValue();            for (int i = 0; i < data.length; i++) {System.out.println("data......" + data[i]);}            if (data != null && data.length > 0) {                final StringBuilder stringBuilder = new StringBuilder(data.length);                for(byte byteChar : data)                //以十六进制的形式输出                    stringBuilder.append(String.format("%02X ", byteChar));               // intent.putExtra(EXTRA_DATA, new String(data) + "\n" + stringBuilder.toString());                intent.putExtra(EXTRA_DATA, new String(data));            }        }        sendBroadcast(intent);    }
发送了广播之后就肯定有广播接收器,这个是在控制蓝牙的activity中,后面再说。

还有几个重要的函数比如readCharacteristic(BluetoothGattCharacteristic characteristic)函数,读取蓝牙中数据。

public void readCharacteristic(BluetoothGattCharacteristic characteristic) {        if (mBluetoothAdapter == null || mBluetoothGatt == null) {            Log.w(TAG, "BluetoothAdapter not initialized");            return;        }        mBluetoothGatt.readCharacteristic(characteristic);    }
有readCharacteristic(BluetoothGattCharacteristic characteristic)函数,当然就有writeCharacteristic(BluetoothGattCharacteristic characteristic),向蓝牙中写入数据。

  public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {        if (mBluetoothAdapter == null || mBluetoothGatt == null) {            Log.w(TAG, "BluetoothAdapter not initialized");            return;        }        mBluetoothGatt.writeCharacteristic(characteristic);    }
另外在这个service中还有其他的一些函数例如初始化initialize()函数、连接蓝牙函数connect(final String address)、断开蓝牙连接函数disconnect()等。
三、蓝牙控制DeviceControlActivity

扫描到蓝牙设备之后就是对蓝牙进行自己需要的控制,比如写数据,读数据,获取设备信息,设备电量等。

在Service中讲到有一个广播,广播接收器就在这个activity中,通过不同的action做出相应的操作。

注册的几种事件

 private static IntentFilter makeGattUpdateIntentFilter() {        final IntentFilter intentFilter = new IntentFilter();        intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);        intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);        intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);        intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);        return intentFilter;    }

// Handles various events fired by the Service.处理服务所激发的各种事件    // ACTION_GATT_CONNECTED: connected to a GATT server.连接一个GATT服务    // ACTION_GATT_DISCONNECTED: disconnected from a GATT server.从GATT服务中断开连接    // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.查找GATT服务    // ACTION_DATA_AVAILABLE: received data from the device.  This can be a result of read    //                        or notification operations.从服务中接受数据    private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {        @Override        public void onReceive(Context context, Intent intent) {            final String action = intent.getAction();            if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {                mConnected = true;                updateConnectionState(R.string.connected);                invalidateOptionsMenu();            } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {                mConnected = false;                updateConnectionState(R.string.disconnected);                invalidateOptionsMenu();                clearUI();            }             //发现有可支持的服务            else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {            //写数据的服务和characteristic            mnotyGattService = mBluetoothLeService.getSupportedGattServices(UUID.fromString("0000ffe5-0000-1000-8000-00805f9b34fb"));                characteristic = mnotyGattService.getCharacteristic(UUID.fromString("0000ffe9-0000-1000-8000-00805f9b34fb"));                //读数据的服务和characteristic                readMnotyGattService = mBluetoothLeService.getSupportedGattServices(UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb"));                readCharacteristic = readMnotyGattService.getCharacteristic(UUID.fromString("0000ffe4-0000-1000-8000-00805f9b34fb"));            }             //显示数据            else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) {            //将数据显示在mDataField上            String data = intent.getStringExtra(BluetoothLeService.EXTRA_DATA);            System.out.println("data----" + data);                displayData(data);            }        }    };    
在发现了有可支持的服务之后会回调Service中的onServicesDiscovered()函数,并发送广播,在官方的demo中发现了可用的Service之后,就查找该BLE设备支持的所有服务和characteristic,在这里不需要查找所有的服务,只需要向蓝牙写数据和读取数据的Service和characteristic的UUID即可。通过查询低功耗蓝牙(BLE)的数据手册可以得到所需要的UUID。

置顶        Android 蓝牙4.0BLE开发实现对蓝牙的写入数据和读取数据

有了这两个Service和characteristic的UUID,就可以对蓝牙发送数据,并发出通知(当写数据发生改变时发出)。

<span style=";">//写数据的服务和characteristic            mnotyGattService = mBluetoothLeService.getSupportedGattServices(UUID.fromString("0000ffe5-0000-1000-8000-00805f9b34fb"));                characteristic = mnotyGattService.getCharacteristic(UUID.fromString("0000ffe9-0000-1000-8000-00805f9b34fb"));                //读数据的服务和characteristic                readMnotyGattService = mBluetoothLeService.getSupportedGattServices(UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb"));                readCharacteristic = readMnotyGattService.getCharacteristic(UUID.fromString("0000ffe4-0000-1000-8000-00805f9b34fb"));</span>
得到这两个Service和characteristic就可以向蓝牙发送数据了。

private void read() {    //mBluetoothLeService.readCharacteristic(readCharacteristic);    //readCharacteristic的数据发生变化,发出通知    mBluetoothLeService.setCharacteristicNotification(readCharacteristic, true);    //Toast.makeText(this, "读成功", Toast.LENGTH_SHORT).show();}
检测readCharacteristic的数据发生变化,发出通知。

向蓝牙发送数据。

read();                final int charaProp = characteristic.getProperties();                                //如果该char可写                if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {                    // If there is an active notification on a characteristic, clear                    // it first so it doesn't update the data field on the user interface.                    if (mNotifyCharacteristic != null) {                        mBluetoothLeService.setCharacteristicNotification( mNotifyCharacteristic, false);                        mNotifyCharacteristic = null;                    }                    //读取数据,数据将在回调函数中                    //mBluetoothLeService.readCharacteristic(characteristic);                    byte[] value = new byte[20];                    value[0] = (byte) 0x00;                    if(edittext_input_value.getText().toString().equals("")){                    Toast.makeText(getApplicationContext(), "请输入!", Toast.LENGTH_SHORT).show();                    return;                    }else{                    WriteBytes = edittext_input_value.getText().toString().getBytes();                    characteristic.setValue(value[0],BluetoothGattCharacteristic.FORMAT_UINT8, 0);                        characteristic.setValue(WriteBytes);                        mBluetoothLeService.writeCharacteristic(characteristic);                        Toast.makeText(getApplicationContext(), "写入成功!", Toast.LENGTH_SHORT).show();                    }                }                if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {                    mNotifyCharacteristic = characteristic;                    mBluetoothLeService.setCharacteristicNotification(characteristic, true);                }                edittext_input_value.setText("");}
一旦数据发生改变,就会发出通知,通知发出后就会调用下面的函数并发出广播。

 @Override        public void onCharacteristicChanged(BluetoothGatt gatt,                                            BluetoothGattCharacteristic characteristic) {            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);        }

10 0
原创粉丝点击