From:http://blog.csdn.net/chenfengdejuanlian/article
/details/45787123
由于最近学校组织了一个移动APP(安卓)设计大赛,自己也学习安卓有一段时间了,就跟同学商量一起去参加试试,一拍即合,然后我们就开始想idea,因为最近可穿戴设备比较火,我们也就想试试。经过商量,我负责Android上位机的开发,同学负责下位机的开发。
上位机的开发主要是低功耗蓝牙BLE的开发,然后就开始找资料,各种找,最后谷歌官方提供的demo还有其他网友基于官方demo修改的demo,结合网上的博客对demo进行理解。刚开始是觉得看起来有点费劲,各种广播,跳来跳去的,刚开始就晕菜了。但是经过三四天的理解,算是把官方的demo理解了。
代码基本上都是官方的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;
- }
- 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);
- }
- };
- 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);
- }
还有几个重要的函数比如readCharacteristic(BluetoothGattCharacteristic characteristic)函数,读取蓝牙中数据。
- public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
- if (mBluetoothAdapter == null || mBluetoothGatt == null) {
- Log.w(TAG, "BluetoothAdapter not initialized");
- return;
- }
- mBluetoothGatt.readCharacteristic(characteristic);
- }
- public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {
- if (mBluetoothAdapter == null || mBluetoothGatt == null) {
- Log.w(TAG, "BluetoothAdapter not initialized");
- return;
- }
- mBluetoothGatt.writeCharacteristic(characteristic);
- }
三、蓝牙控制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和characteristic的UUID,就可以对蓝牙发送数据,并发出通知(当写数据发生改变时发出)。
- <span style="font-size:18px;">//写数据的服务和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>
- private void read() {
- //mBluetoothLeService.readCharacteristic(readCharacteristic);
- //readCharacteristic的数据发生变化,发出通知
- mBluetoothLeService.setCharacteristicNotification(readCharacteristic, true);
- //Toast.makeText(this, "读成功", Toast.LENGTH_SHORT).show();
- }
向蓝牙发送数据。
- 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);
- }
在广播接收器中接收到广播后,把数据显示在EditText上。下面是测试的两张图片。
demo下载地址:BLE 读写