Android L Preview版本出来有一段时间了,最近终于申请下一台Nexus 5,迫不及待地尝试蓝牙广播的功能。(注:主要目的是为自己产品中需要的功能做功能验证,文章涉及具体API的效果,具体使用方式请参考https://developer.android.com/preview/reference.html)
因为没找到博客上如何上传代码,代码(在Android Studio下的项目)链接如下:http://pan.baidu.com/s/1tnbrg。
测试使用的是安装了Android L Preview版本的Nexus 5,扫描数据用的机器是Nexus 4,扫描软件为Bluetooth Le Scanner,如遇到问题或者我的描述错误,请在评论中告知。
1. 开始广播数据
根据API文档,Android L中提供了两种方式开始广播蓝牙数据:
public void startAdvertising (AdvertiseSettingssettings, AdvertisementData advertiseData, AdvertiseCallback callback)
public void startAdvertising (AdvertiseSettingssettings, AdvertisementData advertiseData, AdvertisementData scanResponse,AdvertiseCallback callback)
与iOS不同,Android中蓝牙数据的广播,和其调用的应用程序在前端(Activity的onResume()被调用)或是后端无关,即在(前端/后端)这两种情况下广播的是同一组数据。
问题: 第二个方法中,只有scanResponse可以被扫描到。
在logcat中, 含有GKI_exceptions:
GKI_exception(): 65532 Freeing Linked Buf
另外,开启广播之后,第二个方法无法关闭。
2. AdvertiseCallback
abstract void onFailure(int errorCode)
abstract void onSuccess(AdvertiseSettingssettingsInEffect)
返回的错误代码ErrorCode包含以下五个:
ADVERTISE_FAILED_ALREADY_STARTED
ADVERTISE_FAILED_CONTROLLER_FAILURE
ADVERTISE_FAILED_NOT_STARTED
ADVERTISE_FAILED_SERVICE_UNKNOWN
ADVERTISE_FAILED_TOO_MANY_ADVERTISERS
当startAdvertising()或者stopAdvertising()被调用时,callback中会立即得到结果;如果没有成功执行改操作,那么在onFailure()中将会得到相应的错误代码。
局限:AndroidL中把advertiser的数量限制为4,这里advertiser的概念是在系统层的,app中有一个BluetoothAdvertiser,但跟advertiser的概念不同:advertiser是由BluetoothAdvertiser和AdvertiseCallback共同决定,如果startAdvertising()方法有两次调用,两次使用的BluetoothAdvertiser相同,但AdvertiseCallback不同,那么在系统中,也会有两个advertiser被创建出来;另外advertiser在整个Android系统中最多存在4个,意味着,如果已经打开的app(s)创建了4个advertiser,那么这个app调用startAdvertising()只能得到ADVERTISE_FAILED_TOO_MANY_ADVERTISERS。
3. AdvertiseSettings& AdvertisingSettings.Builder
类AdvertisingSettings.Builder 用于创建AdvertiseSettings,AdvertiseSettings中包含三种数据:AdvertiseMode, Advertise TxPowerLevel和AdvertiseType,其测试结果如下:
AdvertiseMode:
Advertise Mode |
Logcat频率 |
检测到的频率 |
ADVERTISE_MODE_LOW_LATENCY |
1/1600 milliseconds |
1/1068 milliseconds |
ADVERTISE_MODE_BALANCED |
1/400 milliseconds |
1/295 milliseconds |
ADVERTISE_MODE_LOW_POWER |
1/160 milliseconds |
1/142 milliseconds |
问题: ADVERTISE_MODE_LOW_POWER实际上是最耗电的模式,应该是跟ADVERTISE_MODE_LOW_LATENCY弄反了。参考 https://code.google.com/p/android-developer-preview/issues/detail?id=605.这个问题将在下次AndroidL的发布版中解决。
AdvertiseTxPowerLevel:
Advertise Mode |
RSSI scanned |
ADVERTISE_TX_POWER_ULTRA_LOW |
-90dp |
ADVERTISE_TX_POWER_LOW |
-68dp |
ADVERTISE_TX_POWER_MEDIUM |
-61dp |
ADVERTISE_TX_POWER_HIGH |
-54dp |
使用的是Nexus 4和Nexus 5,间隔大约10厘米。
AdvertiseType:
ADVERTISE_TYPE_SCANNABLE
ADVERTISE_TYPE_NON_CONNECTABLE
ADVERTISE_TYPE_CONNECTABLE
Issue:即使Advertisetype 是ADVERTISE_TYPE_NON_CONNECTABLE, 依旧可以看到广播的数据。
4. AdvertisementData& AdvertisementData.Builder
类 AdertisementData.Builder用于创建AdertisementData实例,其长度为31bytes. Five methods available in AdvertisementData.Builder:
AdvertisementData build()
AdvertisementData.Builder setIncludeTxPowerLevel(booleanincludeTxPowerLevel)
AdvertisementData.Builder setManufacturerData(intmanufacturerId, byte[] manufacturerSpecificData)
AdvertisementData.Builder setServiceData(ParcelUuidserviceDataUuid, byte[] serviceData)
AdvertisementData.Builder setServiceUuids(List
对于AdvertisementData,可以设置includeTxPowerLevel为true/manufacture数据/Service数据/Uuids四类数据,并且它们都会占用最后广播的数据的空间,AdvertisementData的最大长度为31bytes。如果超过了31bytes,在调用build()方法时,会抛出IllegalArgumentException异常。
这里有四个实例可以显示这四组数据对广播的数据的影响:
4.1 manufacturedata: manufacturemanufactu, servicedata: s, and setIncludeTxPowerLevel(true)
4.2 manufacturedata: manufacturemanufacture, servicedata: s, and setIncludeTxPowerLevel(false)
4.3 manufacture data: m, service data: serviceservice, andsetIncludeTxPowerLevel(true)
4.4 manufacture data: a, service data: b,setIncludeTxPowerLevel(false), and setServiceUuids(uuidList).
Only one uuid (128 bits) could be set in the uuidList, otherwise theuuidList itself will exceed the 31 bytes limit.
根据上述四组例子,在AndroidL Preview版本中的BluetoothAdvertising功能中AdvertisementData:
a. 对于uuid/manufacture data/servicedata并没有明确的最大长度,但manufacturedata, service data, uuid data, TxPowerLevel data均会占有广播数据的空间,而广播数据最多为31 bytes;
b. 蓝牙数据中的Local name并不能设置。