整理翻译自:https://developer.android.com/guide/topics/connectivity/bluetooth-le.html
首次翻译,内容错误请指正,不明白的地方可以参考原文
在你的应用通过BLE通信之前,你需要检查你的设备是否支持BLE,如果支持,确保已经使能蓝牙功能,如果不支持BLE,那你需要在你应用里优雅的不要使用蓝牙的一些特性 如果你的设备支持BLE,但是被禁用了,你可以在你的程序里使能蓝牙,这项操作可以通过BluetoothAdapter,分两步来完成。 使能蓝牙 1. 获取BluetoothAdapter BlueAdapter操作自身蓝牙,整个系统中只有一个Bluetooth Adapter // Initializes Bluetooth adapter.privateBluetoothAdapter mBluetoothAdapter; finalBluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);mBluetoothAdapter = bluetoothManager.getAdapter(); 2. 使能蓝牙 // 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 =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);} 扫描BLE 设备 你可以通过 startLeScan() 方法查照附近的BLE设备,这个方法需要传入一个BluetoothAdapter.LeScanCallback 的参数,这个参数是一个回调参数,你需要实现其中的回调。扫描操作对电量比较敏感,你需要遵循以下原则: 1. 一旦找到设备就停止扫描 2. 不要在循环中调用扫描,设置一个扫描时间限值,如果先前扫到的设备可能暂时不在扫描的有效距离之内,所以继续扫描有可能耗干电量。 扫描过程: /** * Activity for scanning and displaying available BLE devices. */publicclassDeviceScanActivityextendsListActivity{ privateBluetoothAdapter mBluetoothAdapter; privateboolean mScanning; privateHandler mHandler; // Stops scanning after 10 seconds. privatestaticfinallong SCAN_PERIOD =10000; ... privatevoid scanLeDevice(finalboolean enable){ if(enable){ // Stops scanning after a pre-defined scan period. mHandler.postDelayed(newRunnable(){ @Override publicvoid run(){ mScanning =false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } }, SCAN_PERIOD); mScanning =true; mBluetoothAdapter.startLeScan(mLeScanCallback); }else{ mScanning =false; mBluetoothAdapter.stopLeScan(mLeScanCallback); } ... }...} 如果你只想扫描指定类型的外围设备,你可以调用方法 startLeScan(UUID[], BluetoothAdapter.LeScanCallback),替代上述扫描。这个方法提供了一个UUID 数组 作为程序支持的GATT Server服务的标志。 扫描回调函数 privateBluetoothAdapter.LeScanCallback mLeScanCallback = newBluetoothAdapter.LeScanCallback(){ @Override publicvoid onLeScan(finalBluetoothDevice device,int rssi, byte[] scanRecord){ runOnUiThread(newRunnable(){ @Override publicvoid run(){ mLeDeviceListAdapter.addDevice(device); mLeDeviceListAdapter.notifyDataSetChanged(); } }); }}; 注意:扫描的过程中可以扫到BLE设备,同时也可以扫描到经典蓝牙设备 连接一个 GATT Server 与BLE设备通信的首要步骤就是去连接他,准确的说应该是连接他的GATT Server。您可以调用 connectGatt() 方法 连接一个BLE设备的GATT Server。这个方法有三个形参,Context 对象, 自动连接标志(autoConnect 标志这个设备蓝牙可用时是否自动连接这个BLE设备) 和 BluetoothGattCallback 回调的引用,如下: mBluetoothGatt = device.connectGatt(this,false, mGattCallback); 连接作为主设备的GATT Server,返回了一个 BluetoothGatt 句柄,通过这个句柄你可以进行一些GATT Client的一些操作。调用者就是GATT Client,例如Android应用程序。回调函数BluetoothGattCallback 主要是用来向Client传递一些结果,例如连接状态,以及进一步的GATT Client的操作 在这个例子中,BLE 应用程序提供了一个Activity 来连接,显示数据 显示设备支持的 GATT services 和 characteristics 。Activity 获取用户的输入,与一个被称为BluetoothLeService 的Service进行通信。这个服务通过Android BLE API 与BLE设备进行通信 // A service that interacts with the BLE device via the Android BLE API.publicclassBluetoothLeServiceextendsService{ privatefinalstaticString TAG =BluetoothLeService.class.getSimpleName(); privateBluetoothManager mBluetoothManager; privateBluetoothAdapter mBluetoothAdapter; privateString mBluetoothDeviceAddress; privateBluetoothGatt mBluetoothGatt; privateint mConnectionState = STATE_DISCONNECTED; privatestaticfinalint STATE_DISCONNECTED =0; privatestaticfinalint STATE_CONNECTING =1; privatestaticfinalint STATE_CONNECTED =2; publicfinalstaticString ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED"; publicfinalstaticString ACTION_GATT_DISCONNECTED = "com.example.bluetooth.le.ACTION_GATT_DISCONNECTED"; publicfinalstaticString ACTION_GATT_SERVICES_DISCOVERED = "com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED"; publicfinalstaticString ACTION_DATA_AVAILABLE = "com.example.bluetooth.le.ACTION_DATA_AVAILABLE"; publicfinalstaticString EXTRA_DATA = "com.example.bluetooth.le.EXTRA_DATA"; publicfinalstatic UUID UUID_HEART_RATE_MEASUREMENT = UUID.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT); // Various callback methods defined by the BLE API. privatefinalBluetoothGattCallback mGattCallback = newBluetoothGattCallback(){ @Override publicvoid 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()); }elseif(newState ==BluetoothProfile.STATE_DISCONNECTED){ intentAction = ACTION_GATT_DISCONNECTED; mConnectionState = STATE_DISCONNECTED; Log.i(TAG,"Disconnected from GATT server."); broadcastUpdate(intentAction); } } @Override // New services discovered publicvoid 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 publicvoid onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status){ if(status ==BluetoothGatt.GATT_SUCCESS){ broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); } } ... };...} 当回调被触发后,会调用一个合适的broadcastUpdate() 方法传这个动作 privatevoid broadcastUpdate(finalString action){ finalIntent intent =newIntent(action); sendBroadcast(intent);}privatevoid broadcastUpdate(finalString action, finalBluetoothGattCharacteristic characteristic){ finalIntent intent =newIntent(action); // This is special handling for the Heart Rate Measurement profile. Data // parsing is carried out as per profile specifications. 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."); } finalint 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. finalbyte[] data = characteristic.getValue(); if(data !=null&& data.length >0){ finalStringBuilder stringBuilder =newStringBuilder(data.length); for(byte byteChar : data) stringBuilder.append(String.format("%02X ", byteChar)); intent.putExtra(EXTRA_DATA,newString(data)+"\n"+ stringBuilder.toString()); } } sendBroadcast(intent);} 回到 主Activity(DeviceControlActivity),这些事件主要通过广播 BroadcastReceiver 来传递 // Handles various events fired by the Service.// ACTION_GATT_CONNECTED: connected to a GATT server.// ACTION_GATT_DISCONNECTED: disconnected from a GATT server.// ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services.// ACTION_DATA_AVAILABLE: received data from the device. This can be a// result of read or notification operations.privatefinalBroadcastReceiver mGattUpdateReceiver =newBroadcastReceiver(){ @Override publicvoid onReceive(Context context,Intent intent){ finalString action = intent.getAction(); if(BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)){ mConnected =true; updateConnectionState(R.string.connected); invalidateOptionsMenu(); }elseif(BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)){ mConnected =false; updateConnectionState(R.string.disconnected); invalidateOptionsMenu(); clearUI(); }elseif(BluetoothLeService. ACTION_GATT_SERVICES_DISCOVERED.equals(action)){ // Show all the supported services and characteristics on the // user interface. displayGattServices(mBluetoothLeService.getSupportedGattServices()); }elseif(BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)){ displayData(intent.getStringExtra(BluetoothLeService.EXTRA_DATA)); } }};