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. }  
  • 相关阅读:
    pika的阻塞式使用
    使用 Nuget安装DLL
    StackExchange.Redis的使用
    MongoDB 学习笔记(9)--- Limit与Skip方法
    MongoDB 学习笔记(8)---$type 操作符
    MongoDB学习笔记(7)--- 条件操作符
    MongoDB学习笔记(6)--find
    阿里巴巴Java开发规范手册
    python获取当前文件路径
    断网环境下利用pip安装Python离线安装包
  • 原文地址:https://www.cnblogs.com/syjhsgcc/p/4789883.html
Copyright © 2011-2022 走看看