zoukankan      html  css  js  c++  java
  • 【转】Android BLE开发之Android手机与BLE终端通信

    今天看了一下android 蓝牙BLE 记录一下

    原创作者连接: http://blog.csdn.net/hellogv/ 

    最近穿戴设备发展得很火,把相关技术也带旺了,其中一项是BLE(Bluetooth Low Energy)。BLE是蓝牙4.0的核心Profile,主打功能是快速搜索,快速连接,超低功耗保持连接和传输数据,弱点是数据传输速率低,由于BLE的低功耗特点,因此普遍用于穿戴设备。Android 4.3才开始支持BLE API,所以请各位客官把本文代码运行在蓝牙4.0和Android 4.3及其以上的系统,另外本文所用的BLE终端是一个蓝牙4.0的串口蓝牙模块。

    PS:我的i9100刷了4.4系统后,竟然也能跟BLE蓝牙模块通信。

    BLE分为三部分Service、Characteristic、Descriptor,这三部分都由UUID作为唯一标示符。一个蓝牙4.0的终端可以包含多个Service,一个Service可以包含多个Characteristic,一个Characteristic包含一个Value和多个Descriptor,一个Descriptor包含一个Value。一般来说,Characteristic是手机与BLE终端交换数据的关键,Characteristic有较多的跟权限相关的字段,例如PERMISSION和PROPERTY,而其中最常用的是PROPERTY,本文所用的BLE蓝牙模块竟然没有标准的Characteristic的PERMISSION。Characteristic的PROPERTY可以通过位运算符组合来设置读写属性,例如READ|WRITE、READ|WRITE_NO_RESPONSE|NOTIFY,因此读取PROPERTY后要分解成所用的组合(本文代码已含此分解方法)。

    本文代码改自Android 4.3 Sample的BluetoothLeGatt,把冗余代码去掉,获取的BLE设备信息都通过Log,还有一些必要的读写蓝牙方法,应该算是简化到大家一看就可以懂了。本文代码可以到http://download.csdn.net/detail/hellogv/7228819下载。接下来贴出本文运行的结果,首先是连接BLE设备后,枚举出设备所有Service、Characteristic、Descriptor,并且手机会往Characteristic uuid=0000ffe1-0000-1000-8000-00805f9b34fb写入“send data->”字符串,BLE终端收到数据通过串口传到PC串口助手(见PC串口助手的截图):

    04-21 18:28:25.465: E/DeviceScanActivity(12254): -->service type:PRIMARY
    04-21 18:28:25.465: E/DeviceScanActivity(12254): -->includedServices size:0
    04-21 18:28:25.465: E/DeviceScanActivity(12254): -->service uuid:00001800-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char uuid:00002a00-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
    04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char property:READ
    04-21 18:28:25.465: E/DeviceScanActivity(12254): ---->char uuid:00002a01-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
    04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char property:READ
    04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char uuid:00002a02-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
    04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char property:READ|WRITE|
    04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char uuid:00002a03-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.470: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
    04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char property:READ|WRITE|
    04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char uuid:00002a04-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
    04-21 18:28:25.475: E/DeviceScanActivity(12254): ---->char property:READ
    04-21 18:28:25.475: E/DeviceScanActivity(12254): -->service type:PRIMARY
    04-21 18:28:25.475: E/DeviceScanActivity(12254): -->includedServices size:0
    04-21 18:28:25.475: E/DeviceScanActivity(12254): -->service uuid:00001801-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char uuid:00002a05-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
    04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char property:INDICATE
    04-21 18:28:25.480: E/DeviceScanActivity(12254): -------->desc uuid:00002902-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.480: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
    04-21 18:28:25.480: E/DeviceScanActivity(12254): -->service type:PRIMARY
    04-21 18:28:25.480: E/DeviceScanActivity(12254): -->includedServices size:0
    04-21 18:28:25.480: E/DeviceScanActivity(12254): -->service uuid:0000ffe0-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char uuid:0000ffe1-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char permission:UNKNOW
    04-21 18:28:25.480: E/DeviceScanActivity(12254): ---->char property:READ|WRITE_NO_RESPONSE|NOTIFY|
    04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc uuid:00002902-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
    04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc uuid:00002901-0000-1000-8000-00805f9b34fb
    04-21 18:28:25.490: E/DeviceScanActivity(12254): -------->desc permission:UNKNOW
    04-21 18:28:26.025: E/DeviceScanActivity(12254): onCharRead BLE DEVICE read 0000ffe1-0000-1000-8000-00805f9b34fb -> 00

    这里红字是由BluetoothGattCallback的onCharacteristicRead()回调而打出Log

    以下Log是PC上的串口工具通过BLE模块发送过来,由BluetoothGattCallback的 onCharacteristicChanged()打出Log
    04-21 18:30:18.260: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
    04-21 18:30:18.745: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
    04-21 18:30:19.085: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
    04-21 18:30:19.350: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
    04-21 18:30:19.605: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
    04-21 18:30:19.835: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
    04-21 18:30:20.055: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
    04-21 18:30:20.320: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
    04-21 18:30:20.510: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
    04-21 18:30:20.735: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone
    04-21 18:30:21.000: E/DeviceScanActivity(12254): onCharWrite BLE DEVICE write 0000ffe1-0000-1000-8000-00805f9b34fb -> send data to phone

    接下来贴出本文核心代码:

      1. public class DeviceScanActivity extends ListActivity {  
      2.     private final static String TAG = DeviceScanActivity.class.getSimpleName();  
      3.     private final static String UUID_KEY_DATA = "0000ffe1-0000-1000-8000-00805f9b34fb";  
      4.   
      5.     private LeDeviceListAdapter mLeDeviceListAdapter;  
      6.     /**搜索BLE终端*/  
      7.     private BluetoothAdapter mBluetoothAdapter;  
      8.     /**读写BLE终端*/  
      9.     private BluetoothLeClass mBLE;  
      10.     private boolean mScanning;  
      11.     private Handler mHandler;  
      12.   
      13.     // Stops scanning after 10 seconds.  
      14.     private static final long SCAN_PERIOD = 10000;  
      15.   
      16.     @Override  
      17.     public void onCreate(Bundle savedInstanceState) {  
      18.         super.onCreate(savedInstanceState);  
      19.         getActionBar().setTitle(R.string.title_devices);  
      20.         mHandler = new Handler();  
      21.   
      22.         // Use this check to determine whether BLE is supported on the device.  Then you can  
      23.         // selectively disable BLE-related features.  
      24.         if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {  
      25.             Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();  
      26.             finish();  
      27.         }  
      28.   
      29.         // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to  
      30.         // BluetoothAdapter through BluetoothManager.  
      31.         final BluetoothManager bluetoothManager =  
      32.                 (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);  
      33.         mBluetoothAdapter = bluetoothManager.getAdapter();  
      34.           
      35.         // Checks if Bluetooth is supported on the device.  
      36.         if (mBluetoothAdapter == null) {  
      37.             Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show();  
      38.             finish();  
      39.             return;  
      40.         }  
      41.         //开启蓝牙  
      42.         mBluetoothAdapter.enable();  
      43.           
      44.         mBLE = new BluetoothLeClass(this);  
      45.         if (!mBLE.initialize()) {  
      46.             Log.e(TAG, "Unable to initialize Bluetooth");  
      47.             finish();  
      48.         }  
      49.         //发现BLE终端的Service时回调  
      50.         mBLE.setOnServiceDiscoverListener(mOnServiceDiscover);  
      51.         //收到BLE终端数据交互的事件  
      52.         mBLE.setOnDataAvailableListener(mOnDataAvailable);  
      53.     }  
      54.   
      55.   
      56.     @Override  
      57.     protected void onResume() {  
      58.         super.onResume();  
      59.   
      60.         // Initializes list view adapter.  
      61.         mLeDeviceListAdapter = new LeDeviceListAdapter(this);  
      62.         setListAdapter(mLeDeviceListAdapter);  
      63.         scanLeDevice(true);  
      64.     }  
      65.   
      66.     @Override  
      67.     protected void onPause() {  
      68.         super.onPause();  
      69.         scanLeDevice(false);  
      70.         mLeDeviceListAdapter.clear();  
      71.         mBLE.disconnect();  
      72.     }  
      73.   
      74.     @Override  
      75.     protected void onStop() {  
      76.         super.onStop();  
      77.         mBLE.close();  
      78.     }  
      79.       
      80.     @Override  
      81.     protected void onListItemClick(ListView l, View v, int position, long id) {  
      82.         final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position);  
      83.         if (device == null) return;  
      84.         if (mScanning) {  
      85.             mBluetoothAdapter.stopLeScan(mLeScanCallback);  
      86.             mScanning = false;  
      87.         }  
      88.           
      89.         mBLE.connect(device.getAddress());  
      90.     }  
      91.   
      92.     private void scanLeDevice(final boolean enable) {  
      93.         if (enable) {  
      94.             // Stops scanning after a pre-defined scan period.  
      95.             mHandler.postDelayed(new Runnable() {  
      96.                 @Override  
      97.                 public void run() {  
      98.                     mScanning = false;  
      99.                     mBluetoothAdapter.stopLeScan(mLeScanCallback);  
      100.                     invalidateOptionsMenu();  
      101.                 }  
      102.             }, SCAN_PERIOD);  
      103.   
      104.             mScanning = true;  
      105.             mBluetoothAdapter.startLeScan(mLeScanCallback);  
      106.         } else {  
      107.             mScanning = false;  
      108.             mBluetoothAdapter.stopLeScan(mLeScanCallback);  
      109.         }  
      110.         invalidateOptionsMenu();  
      111.     }  
      112.   
      113.     /** 
      114.      * 搜索到BLE终端服务的事件 
      115.      */  
      116.     private BluetoothLeClass.OnServiceDiscoverListener mOnServiceDiscover = new OnServiceDiscoverListener(){  
      117.   
      118.         @Override  
      119.         public void onServiceDiscover(BluetoothGatt gatt) {  
      120.             displayGattServices(mBLE.getSupportedGattServices());  
      121.         }  
      122.           
      123.     };  
      124.       
      125.     /** 
      126.      * 收到BLE终端数据交互的事件 
      127.      */  
      128.     private BluetoothLeClass.OnDataAvailableListener mOnDataAvailable = new OnDataAvailableListener(){  
      129.   
      130.         /** 
      131.          * BLE终端数据被读的事件 
      132.          */  
      133.         @Override  
      134.         public void onCharacteristicRead(BluetoothGatt gatt,  
      135.                 BluetoothGattCharacteristic characteristic, int status) {  
      136.             if (status == BluetoothGatt.GATT_SUCCESS)   
      137.                 Log.e(TAG,"onCharRead "+gatt.getDevice().getName()  
      138.                         +" read "  
      139.                         +characteristic.getUuid().toString()  
      140.                         +" -> "  
      141.                         +Utils.bytesToHexString(characteristic.getValue()));  
      142.         }  
      143.           
      144.         /** 
      145.          * 收到BLE终端写入数据回调 
      146.          */  
      147.         @Override  
      148.         public void onCharacteristicWrite(BluetoothGatt gatt,  
      149.                 BluetoothGattCharacteristic characteristic) {  
      150.             Log.e(TAG,"onCharWrite "+gatt.getDevice().getName()  
      151.                     +" write "  
      152.                     +characteristic.getUuid().toString()  
      153.                     +" -> "  
      154.                     +new String(characteristic.getValue()));  
      155.         }  
      156.     };  
      157.   
      158.     // Device scan callback.  
      159.     private BluetoothAdapter.LeScanCallback mLeScanCallback =  
      160.             new BluetoothAdapter.LeScanCallback() {  
      161.   
      162.         @Override  
      163.         public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {  
      164.             runOnUiThread(new Runnable() {  
      165.                 @Override  
      166.                 public void run() {  
      167.                     mLeDeviceListAdapter.addDevice(device);  
      168.                     mLeDeviceListAdapter.notifyDataSetChanged();  
      169.                 }  
      170.             });  
      171.         }  
      172.     };  
      173.   
      174.     private void displayGattServices(List<BluetoothGattService> gattServices) {  
      175.         if (gattServices == null) return;  
      176.   
      177.         for (BluetoothGattService gattService : gattServices) {  
      178.             //-----Service的字段信息-----//  
      179.             int type = gattService.getType();  
      180.             Log.e(TAG,"-->service type:"+Utils.getServiceType(type));  
      181.             Log.e(TAG,"-->includedServices size:"+gattService.getIncludedServices().size());  
      182.             Log.e(TAG,"-->service uuid:"+gattService.getUuid());  
      183.               
      184.             //-----Characteristics的字段信息-----//  
      185.             List<BluetoothGattCharacteristic> gattCharacteristics =gattService.getCharacteristics();  
      186.             for (final BluetoothGattCharacteristic  gattCharacteristic: gattCharacteristics) {  
      187.                 Log.e(TAG,"---->char uuid:"+gattCharacteristic.getUuid());  
      188.                   
      189.                 int permission = gattCharacteristic.getPermissions();  
      190.                 Log.e(TAG,"---->char permission:"+Utils.getCharPermission(permission));  
      191.                   
      192.                 int property = gattCharacteristic.getProperties();  
      193.                 Log.e(TAG,"---->char property:"+Utils.getCharPropertie(property));  
      194.   
      195.                 byte[] data = gattCharacteristic.getValue();  
      196.                 if (data != null && data.length > 0) {  
      197.                     Log.e(TAG,"---->char value:"+new String(data));  
      198.                 }  
      199.   
      200.                 //UUID_KEY_DATA是可以跟蓝牙模块串口通信的Characteristic  
      201.                 if(gattCharacteristic.getUuid().toString().equals(UUID_KEY_DATA)){                    
      202.                     //测试读取当前Characteristic数据,会触发mOnDataAvailable.onCharacteristicRead()  
      203.                     mHandler.postDelayed(new Runnable() {  
      204.                         @Override  
      205.                         public void run() {  
      206.                             mBLE.readCharacteristic(gattCharacteristic);  
      207.                         }  
      208.                     }, 500);  
      209.                       
      210.                     //接受Characteristic被写的通知,收到蓝牙模块的数据后会触发mOnDataAvailable.onCharacteristicWrite()  
      211.                     mBLE.setCharacteristicNotification(gattCharacteristic, true);  
      212.                     //设置数据内容  
      213.                     gattCharacteristic.setValue("send data->");  
      214.                     //往蓝牙模块写入数据  
      215.                     mBLE.writeCharacteristic(gattCharacteristic);  
      216.                 }  
      217.                   
      218.                 //-----Descriptors的字段信息-----//  
      219.                 List<BluetoothGattDescriptor> gattDescriptors = gattCharacteristic.getDescriptors();  
      220.                 for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) {  
      221.                     Log.e(TAG, "-------->desc uuid:" + gattDescriptor.getUuid());  
      222.                     int descPermission = gattDescriptor.getPermissions();  
      223.                     Log.e(TAG,"-------->desc permission:"+ Utils.getDescPermission(descPermission));  
      224.                       
      225.                     byte[] desData = gattDescriptor.getValue();  
      226.                     if (desData != null && desData.length > 0) {  
      227.                         Log.e(TAG, "-------->desc value:"+ new String(desData));  
      228.                     }  
      229.                  }  
      230.             }  
      231.         }//  
      232.   
      233.     }  
      234. }  
  • 相关阅读:
    Educational Codeforces Round 83 --- F. AND Segments
    Educational Codeforces Round 83 --- G. Autocompletion
    SEERC 2019 A.Max or Min
    2019-2020 ICPC Southwestern European Regional Programming Contest(Gym 102501)
    Educational Codeforces Round 78 --- F. Cards
    今天我学习了一门全新的语言
    codeforces 1323D 题解(数学)
    Educational Codeforces Round 80 (Div. 2) 题解 1288A 1288B 1288C 1288D 1288E
    Educational Codeforces Round 81 (Div. 2) 题解 1295A 1295B 1295C 1295D 1295E 1295F
    Codeforces Round #617 (Div. 3) 题解 1296C 1296D 1296E 1296F
  • 原文地址:https://www.cnblogs.com/syjhsgcc/p/4789883.html
Copyright © 2011-2022 走看看