FireBLE

FireBLE 是一个面向于打造智能生活的开源平台,以BLE(Bluetooth Low Energy)技术为核心,拥有超低的功耗、不俗的处理能力和广泛的应用场合,专注于更智能、高效率的工作模式,让生活在科技中更安全、方便、快捷。也许您一个不经意的想法与FireBLE擦出的火花,会在这片原野上燎出火焰,甚至燃烧整个世界。

开发入门

更新时间:2017-08-08 阅读:3814

Android BLE

Android的4.3(API Level 18)引入了蓝牙低耗能的内置平台支持,提供相应的API,应用程序可以用它来发现设备,查询服务,和读/写特征。在对比传统蓝牙,蓝牙低功耗(BLE)被设计成更低的功耗,这允许Android应用使用具有低功率的设备,如接近传感器,心脏速率显示器,健身设备,等等BLE设备。

基本概念

  • Generic Attribute Profile (GATT) GATT是在BLE连接中用以接收和发送属性数据的通用规格。
  • Attribute Protocol (ATT) 属性协议是以UUID来标识属性的协议。
  • Characteristic 特征包含一个值和0或n个描述该值的描述符。
  • Descriptor 描述符是一个用以描述特征值的属性。
  • Service 服务是是特征的集合。

角色和职责

角色分为中央(Central)和周边(peripheral),以Android手机和BLE心脏速率显示器为例,Android手机的角色就是中央,它的职责是控制BLE心脏速率显示器;而BLE心脏速率显示器的角色是周边,它的职责是响应Android手机的控制。

BLE权限

在BLE开发中,Android应用需要以下权限:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
另外,应用判断存不存在BLE特性,可以在AndroidManifest.xml中加入:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
而在代码中,可以这样判断:

 // Use this check to determine whether BLE is supported on the device. Then
 // you can selectively disable BLE-related features.
 if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
     Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
     finish();
 }

BLE开发

设置BLE

1.获取BluetoothAdapter

 // Initializes Bluetooth adapter.
 final BluetoothManager bluetoothManager =
         (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
 mBluetoothAdapter = bluetoothManager.getAdapter();

2.打开蓝牙

 private BluetoothAdapter mBluetoothAdapter;
 ...
 // Ensures Bluetooth is available on the device and it is enabled. If not,
 // displays a dialog requesting user permission to enable Bluetooth.
 if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
     Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
     startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
 }

查找BLE设备

要查找BLE设备,你要调用startLeScan()方法,这个方法以一个BluetoothAdapter.LeScanCallback对象作为参数。停止查找,你要调用stopLeScan()方法,这个方法以一个BluetoothAdapter.LeScanCallback对象作为参数。

 /**
  * Activity for scanning and displaying available BLE devices.
  */
 public class DeviceScanActivity extends ListActivity {
 
     private BluetoothAdapter mBluetoothAdapter;
     private boolean mScanning;
     private Handler mHandler;
 
     // Stops scanning after 10 seconds.
     private static final long SCAN_PERIOD = 10000;
     ...
     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);
                 }
             }, SCAN_PERIOD);
 
             mScanning = true;
             mBluetoothAdapter.startLeScan(mLeScanCallback);
         } else {
             mScanning = false;
             mBluetoothAdapter.stopLeScan(mLeScanCallback);
         }
         ...
     }
 ...
     private LeDeviceListAdapter mLeDeviceListAdapter;
 ...
     // Device scan callback.
     private BluetoothAdapter.LeScanCallback mLeScanCallback =
             new BluetoothAdapter.LeScanCallback() {
       @Override
       public void onLeScan(final BluetoothDevice device, int rssi,
               byte[] scanRecord) {
           runOnUiThread(new Runnable() {
              @Override
              public void run() {
                  mLeDeviceListAdapter.addDevice(device);
                  mLeDeviceListAdapter.notifyDataSetChanged();
              }
           });
        }
     };
 }

连接到GATT Server

连接设备调用connectGatt()方法,这个方法有3个参数,一个Context对象,一个表示自动连接的布尔值,一个BluetoothGattCallback对象:

 mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
 BluetoothGattCallback是一个BLE连接状态的回调:
     // Various callback methods defined by the BLE API.
     private final BluetoothGattCallback mGattCallback =
             new BluetoothGattCallback() {
         @Override
         public void onConnectionStateChange(BluetoothGatt gatt, int status,
                 int newState) {
             String intentAction;
             if (newState == BluetoothProfile.STATE_CONNECTED) {
                 intentAction = ACTION_GATT_CONNECTED;
                 mConnectionState = STATE_CONNECTED;
                 broadcastUpdate(intentAction);
                 Log.i(TAG, "Connected to GATT server.");
                 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
         // New services discovered
         public void onServicesDiscovered(BluetoothGatt gatt, int status) {
             if (status == BluetoothGatt.GATT_SUCCESS) {
                 broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
             } else {
                 Log.w(TAG, "onServicesDiscovered received: " + status);
             }
         }
 
         @Override
         // Result of a characteristic read operation
         public void onCharacteristicRead(BluetoothGatt gatt,
                 BluetoothGattCharacteristic characteristic,
                 int status) {
             if (status == BluetoothGatt.GATT_SUCCESS) {
                 broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
             }
         }
      ...
     };

读GATT属性

读GATT属性要调用readCharacteristic()方法,这个方法有一个BluetoothGattCharacteristic对象作为参数:

     public boolean readCharacteristic(UUID gatservice_uuid,UUID char_uuid){
     	synchronized(mGattLock){
     		try{
 		    	if(mBluetoothGatt==null || mBluetoothGattServiceList==null) return false;
 		    	BluetoothGattService bgs = mBluetoothGatt.getService(gatservice_uuid);
 		    	if(bgs==null) return false;
 		    	BluetoothGattCharacteristic bgc = bgs.getCharacteristic(char_uuid);
 		    	if(bgc==null) return false;
 		    	int properties = bgc.getProperties();
 		    	if(((properties&BluetoothGattCharacteristic.PROPERTY_READ ) == BluetoothGattCharacteristic.PROPERTY_READ ))
 				{
 		    		return mBluetoothGatt.readCharacteristic(bgc);
 				}else{
 					LOGD(gatservice_uuid+"->"+char_uuid+" can not read !");
 					return false;
 				}
     		}catch(Exception ex){
     			return false ;
     		}
     	}
     }

写GATT属性

读GATT属性要调用writeCharacteristic()方法,这个方法有一个BluetoothGattCharacteristic对象作为参数:

     public boolean writeCharacteristic(UUID gatservice_uuid,UUID char_uuid,String value){
     	synchronized(mGattLock){
     		try{
 		    	if(mBluetoothGatt==null || mBluetoothGattServiceList==null) return false;
 		    	BluetoothGattService bgs = mBluetoothGatt.getService(gatservice_uuid);
 		    	if(bgs==null){
 		    		LOGD("bgs:"+bgs+"->"+" can not find ! write error");
 		    		return false;
 		    	}
 		    	BluetoothGattCharacteristic bgc = bgs.getCharacteristic(char_uuid);
 		    	if(bgc==null) {
 		    		LOGD("bgc:"+bgc+"->"+" can not find ! write error");
 		    		return false;
 		    	}
 		    	int properties = bgc.getProperties();
 		    	if( ( ( properties&BluetoothGattCharacteristic.PROPERTY_WRITE ) == BluetoothGattCharacteristic.PROPERTY_WRITE )
 		    			|| ( ( properties&BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE ) == BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE )
 		    			|| ( ( properties&BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE ) == BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE ) )
 				{
 		    		bgc.setValue(value);
 		    		return mBluetoothGatt.writeCharacteristic(bgc);
 				}else{
 					LOGD(gatservice_uuid+"->"+char_uuid+" can not write !");
 					return false;
 				}
     		}catch(Exception ex){
     			LOGD("writeCharacteristic mBluetoothGatt dead .");
     			return false ;
     		}
     	}
     }

接收BLE通知

接收BLE通知要调用setCharacteristicNotification()方法,这方法有一个BluetoothGattDescriptor对象作为参数:

     private static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
     public boolean setCharacteristicNotification(UUID gatservice_uuid,UUID char_uuid,boolean enable){
     	synchronized(mGattLock){
     		try{
 		    	if(mBluetoothGatt==null || mBluetoothGattServiceList==null) return false;
 		    	BluetoothGattService bgs = mBluetoothGatt.getService(gatservice_uuid);
 		    	if(bgs==null) return false;
 		    	BluetoothGattCharacteristic bgc = bgs.getCharacteristic(char_uuid);
 		    	if(bgc==null) return false;
 		    	int properties = bgc.getProperties();
 		    	if((properties&BluetoothGattCharacteristic.PROPERTY_NOTIFY ) == BluetoothGattCharacteristic.PROPERTY_NOTIFY )
 				{
 		    		if(mBluetoothGatt.setCharacteristicNotification(bgc,enable))
 		    		{
 		    			BluetoothGattDescriptor descriptor = bgc.getDescriptor(UUID.fromString(CLIENT_CHARACTERISTIC_CONFIG));
 		                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
 		                return mBluetoothGatt.writeDescriptor(descriptor);
 		    		}else{
 		    			return false;
 		    		}
 				}else{
 					LOGD(gatservice_uuid+"->"+char_uuid+" can not notify !");
 					return false;
 				}
   		}catch(Exception ex){
     			LOGD("setCharacteristicNotification mBluetoothGatt dead .");
     			return false ;
     		}
     	}
     }

关闭客户端应用

使用完BLE设备,需要调用close()方法:

 public void close() {
     if (mBluetoothGatt == null) {
         return;
     }
     mBluetoothGatt.close();
     mBluetoothGatt = null;
 }