【轉】Android BLE開發之Android手機與BLE終端通訊

今天看了一下android 藍牙BLE 記錄一下java

原創做者鏈接: http://blog.csdn.net/hellogv/ android

最近穿戴設備發展得很火,把相關技術也帶旺了,其中一項是BLE(Bluetooth Low Energy)。BLE是藍牙4.0的核心Profile,主打功能是快速搜索,快速鏈接,超低功耗保持鏈接和傳輸數據,弱點是數據傳輸速率低,因爲BLE的低功耗特色,所以廣泛用於穿戴設備。Android 4.3纔開始支持BLE API,因此請各位客官把本文代碼運行在藍牙4.0和Android 4.3及其以上的系統,另外本文所用的BLE終端是一個藍牙4.0的串口藍牙模塊。ide

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後要分解成所用的組合(本文代碼已含此分解方法)。post

 

本文代碼改自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 -> 00ui

這裏紅字是由BluetoothGattCallback的onCharacteristicRead()回調而打出Logthis

 

 

如下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 phonespa

接下來貼出本文核心代碼:.net

 

[java]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
 
    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. }  
相關文章
相關標籤/搜索