AndroidBluetoothLowEnergy(Android低功耗蓝⽛)
Android 4.3(API Level 18)开始引⼊Bluetooth Low Energy(BLE,低功耗蓝⽛)的核⼼功能并提供了相应的API,应⽤程序通过这些api 可以扫描设备、查询rvices,读写设备的characteristics(属性特征)。对⽐传统的蓝⽛,BLE的设计能够显著减低功耗。这让Android应⽤程序与BLE设备之间的低功耗通讯成为可能,例如距离传感器、⼼率监视器、健⾝设备等等。
1、关键术语和概念
1.1 下⾯是⼀些BLE关键术语和概念的摘要:
* Generic Attribute Profile(GATT):GATT profile是⼀种关于发送和接收简短数据⽚段的⼀般规范,这种简短数据⽚段例如在BLE的* Generic Attribute Profile(GATT):
连接上众所周知的“attribute(属性)”等。当前所有低功耗应⽤程序的profile都基于GATT。另外,蓝⽛技术联盟(Bluetooth SIG)已经为很多BLE设备定义了profile。profile就是⼀种在指定的应⽤程序中定义设备如何⼯作的规范。注意,⼀台设备可以实现多个profile。例如,⼀台设备可以包含⼼率监视器和电池电量探测器。
* Attribute Protocol(ATT,属性协议):GATT构建在ATT的基础之上,因此也总被成为GATT/ATT。AT
T针对BLE设备的运⾏进⾏了* Attribute Protocol(ATT,属性协议):
优化。为此,它会尽可能的使⽤更少的字节数据。每⼀个属性都通过UUID来唯⼀确定。UUID就是⼀个标准128位格式的字符串ID,⽤于唯⼀确定⼀个信息。属性通过ATT协议格式化为characteristics和rvices后进⾏传输。
* Characteristic:⼀个characteristic中包含⼀个值,以及0个或多个⽤于描述characteristic值的descriptor。可以将characteristic认为* Characteristic:
是⼀种类型,类似于⼀个类。
factor
* Descriptor:Descriptor(描述符)中定义的属性⽤于描述⼀个characteristic值。例如,⼀个descriptor可以为⼀个characteristic的值指* Descriptor:
定⼀个在可接受范围内的可读性描述,或者为⼀个characteristic的值指定⼀个计量单位。
Service:
* Service
⼀个rvice是⼀个characteristic的集合。例如,你可以持有⼀个名为“⼼率监视器”的rvice,它包含的characteristic例如“⼼率测量”。你可以在上找到⼀系列基于GATT的profile和rvice。
1.2 ⾓⾊和职能
以下是⼀台Android设备与BLE设备交互时的⼀些适⽤⾓⾊和职能:
* 中央设备和外围设备。这适⽤于BLE⾃⾝的连接。担任中央设备⾓⾊的设备负责扫描和搜索⼴告,担任外围设备的⾓⾊负责发送⼴告。
* 中央设备和外围设备。
* GATT服务端和GATT客户端。
* GATT服务端和GATT客户端。这取决于两台设备在建⽴连接后如何互相通信。
为了理解这之间的区别,想象你有⼀台Android⼿机和⼀台BLE设备作为活动追踪器。⼿机将担任中央设备⾓⾊;活动追踪器将担任外围设备⾓⾊(你需要具备两种⾓⾊才能建⽴⼀个BLE连接,两者都担任外围设备⾓⾊不能互相通信,同样两者都担任中央设备⾓⾊也不能互相通信)。
⼀旦⼿机和活动追踪器建⽴连接,它们就可以互相传输GATT媒体数据。根据它们传输的数据,其中⼀⽅需要担任服务端的⾓⾊。例如,如果活动追踪器想要发送传感器数据给⼿机,活动追踪器就需要担任服务端的⾓⾊。如果活动追踪器想要接收⼿机的数据,⼿机就需要担任服务端的⾓⾊。在本⽚⽂档的例⼦中,Android应⽤程序(运⾏在Android设备上)是GATT客户端。应⽤程序从GATT服务端获取数据,这个服务端由⽀
持Heart Rate Profile的BLE⼼率监视器设备担任。但是你可以交替让你的Android应⽤程序扮演GATT服务端的⾓⾊。具体参
考BluetoothGattService。
2、BLE Permissions(BLE权限)
android.permission.BLUETOOTH权限。你需要这个权限来执⾏⼀些蓝⽛通信的为了在你的应⽤程序中使⽤Bluetooth的功能,你必须声明android.permission.BLUETOOTH
操作,例如请求链接,接受连接,还有传输数据。
android.permission.BLUETOOTH_ADMIN权限。注意,如果如果你想让你的应⽤程序进⾏设备扫描或者管理蓝⽛设置,你必须同时声明android.permission.BLUETOOTH_ADMIN
你使⽤BLUETOOTH_ADMIN权限,你必须同时声明BLUETOOTH权限。
在你的应⽤程序manifest⽂件中声明蓝⽛权限,例如:
<us-permission android:name="android.permission.BLUETOOTH"/>
<us-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
如果你想声明你的应⽤程序只能在⽀持BLE的设备上运⾏,可以将下⾯声明包含进你的应⽤程序manifest⽂件中:
<us-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
然⽽,如果你想让你的应⽤程序也能够在不⽀持BLE的设备上运⾏,你就应该将上⾯标签中的属性设置为required="fal"。然后在运⾏的过程中使⽤PackageManager.hasSystemFeature()⽅法来判断设备是否⽀持BLE:
// 使⽤下⾯的⽅法来确定设备是否⽀持BLE, 然后你可以选择禁⽤BLE的功能
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
除此之外英语}
3、Setting Up BLE(设置BLE)
在你的应⽤程序通过BLE进⾏通信之前,你需要确认设备是否⽀持BLE。如果⽀持,还要再确认是否已经启⽤。注意这个检查步骤只有在&/>设置为fal的情况下才需要执⾏。
如果不⽀持BLE,你应该优雅的禁⽌⼀些使⽤BLE的功能。如果⽀持BLE,但是⽬前禁⽤了,那么你需要在不离开你的应⽤程序状态下,请求⽤户启⽤蓝⽛⽤能。这个过程需要使⽤BluetoothAdapter,分两个步骤完成:
3.1 获取BluetoothAdapter。
基本上所有使⽤蓝⽛的activity都需要BluetoothAdapter。BluetoothAdapter代表了设备本⾝的蓝⽛适配器(蓝⽛发送接收器)。在整个系统中有⼀个BluetoothAdapter对象,你的应⽤程序可以使⽤这个对象进⾏交互。下⾯的代码⽚段展⽰了如果获取这个适配器。注意下⾯的这种⽅法使⽤getSystemServic
e()⽅法来获取⼀个BluetoothManager实例,之后再通过BluetoothManager获取BluetoothAdapter。Android
opinion是什么意思4.3(API Level 18)才开始⽀持BluetoothManager:
// 初始化蓝⽛适配器.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = Adapter();
3.2 启⽤蓝⽛
下⼀步,你需要确保蓝⽛已经启动。调⽤isEnable()⽅法来检查蓝⽛当前是否已经启⽤。如果⽅法返回fal,说明蓝⽛被禁⽤了。下⾯的代码⽚段中检查蓝⽛是否已经启⽤。如果没有启⽤,代码⽚段会显⽰⼀个错误提⽰⽤户去设置中启⽤蓝⽛:
private BluetoothAdapter mBluetoothAdapter;
.hartz
..
// 确认设备⽀持蓝⽛并且已经启⽤. 如果没有,
// 显⽰⼀个对话框要求⽤户授权启⽤蓝⽛.redeem
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
4、Finding BLE Devices(搜索BLE设备)
搜索BLE设备,你可以使⽤startLeScan()⽅法。这个⽅法需要⼀个BluetoothAdapter.LeScanCallback对象作为参数。你必须实现这个callback接⼝,因为扫描的结果会通过这个接⼝返回。由于搜索设备是⽐较耗电的操作,你应该遵循以下指南使⽤:
* ⼀旦你找到⽬标设备,应该马上停⽌搜索。
* 不要死循环搜索,并设置搜索的最长时间。⼀台以前可以访问的设备可能已经移出了可检测范围,继续扫描只会消耗电量。
下⾯的代码⽚段展⽰了如何开始和停⽌搜索:
/**
* 扫描和显⽰可访问BLE设备的Activity.
*/
public class DeviceScanActivity extends ListActivity {
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;英文男孩名字
// 10秒钟后停⽌扫描.
airraid
private static final long SCAN_PERIOD = 10000;
...
private void scanLeDevice(final boolean enable) {
if (enable) {
// 在预定义的扫描时间周期后停⽌扫描.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = fal;
ttamBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} el {
mScanning = fal;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
...
}
...
}
如果你只想搜索指定类型的外围设备,你可以替换成startLeScan(UUID[], BluetoothAdapter.LeScanC
allback)⽅法,并提供⼀个你的应⽤程序所⽀持的GATT服务的UUID对象数组。
下⾯是⼀个BluetoothAdapter.LeScanCallback的实现,它是⼀个⽤于接收BLE搜索结果的接⼝:
private LeDeviceListAdapter mLeDeviceListAdapter;
...
// 设备搜索回调接⼝.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
poempublic void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
}
});
}
};
注意:正如Bluetooth⽂档中所描述的,在同⼀个时间你只能搜索BLE设备或者搜索传统蓝⽛设备。你不能同时搜索BLE设备和传统蓝⽛设备。
5、Connecting to a GATT Server(连接⼀个GATT服务)
与BLE设备交互的第⼀步就是要连接上它——更准确的说,是连接设备上的GATT服务。连接BLE设备上的GATT服务,你可以使⽤
connectGatt()⽅法。这个⽅法需要三个参数:⼀个Context对象,autoConnect(⼀个表⽰是否当BLE设备可访问时马上⾃动连接的boolean 值),还有⼀个BluetoothGattCallbackduixiang:
mBluetoothGatt = tGatt(this,fal, mGattCallback);
上⾯的代码会连接BLE设备管理的GATT服务,并返回⼀个BluetoothGatt实例,通过这个实例就可以执⾏GATT客户端的相关操作。这个调⽤者(Android应⽤程序)就是GATT客户端。⾥⾯的BluetoothGattCallback对象⽤于交付操作结果给客户端,例如连接状态,还有将来⼀些GATT 客户端操作的结果。
在这个例⼦中,BLE应⽤程序提供了⼀个activity(DeviceControlActivity)来连接、显⽰数据,和显⽰BLE设备所⽀持的GATT的rvice以及characteristic。基于⽤户的输⼊,这个activity会和⼀个名为BluetoothLeService的Service通信,这个rvice通过Android BLE的API与BLE 设备进⾏交互。
// ⼀个通过Android BLE API与BLE设备进⾏交互的rvice.
public class BluetoothLeService extends Service {
private final static String TAG = SimpleName();
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private String mBluetoothDeviceAddress;
private BluetoothGatt mBluetoothGatt;
private int mConnectionState = STATE_DISCONNECTED;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
public final static String ACTION_GATT_CONNECTED =
"ample.bluetooth.le.ACTION_GATT_CONNECTED";
英语文章听力
public final static String ACTION_GATT_DISCONNECTED =
"ample.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"ample.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =