7、BLE广播(Advertising):AdvertiseSettings与AdvertiseData的配置、广播回调、兼容性处理(Android 8+限制)、扩展广播(5.0+)
BLE广播,说白了就是让你的手机像个小喇叭一样,不停喊:“我在这儿!我在这儿!我能提供这些服务!” 其他设备听到后,就可以决定要不要连过来。
我个人习惯把广播比作“蓝牙世界的名片”。你想想看,名片上印什么内容、用什么字体、多大尺寸,这些都得精心设计。在Android里,AdvertiseSettings和AdvertiseData就是设计这张名片的工具。
7.1 AdvertiseSettings:广播的“物理层”配置
先说说AdvertiseSettings。它控制的是广播的物理行为,比如功率、模式、通道等。我刚开始做BLE开发时,经常忽略这些参数,结果要么广播距离太短,要么功耗高得吓人。
| 参数 | 可选值 | 说明 |
|---|---|---|
| AdvertiseMode | ADVERTISE_MODE_LOW_POWER / BALANCED / LOW_LATENCY | 广播间隔:低功耗约1000ms,平衡约250ms,低延迟约100ms |
| TxPowerLevel | ADVERTISE_TX_POWER_ULTRA_LOW / LOW / MEDIUM / HIGH | 发射功率,直接影响广播距离 |
| AdvertiseType | ADVERTISE_TYPE_CONNECTABLE / NON_CONNECTABLE / SCANNABLE | 是否可连接、可扫描 |
| Timeout | 0~180000 ms | 广播超时时间,0表示持续广播 |
核心经验:我在项目中遇到过,有些手机在低功耗模式下广播间隔会漂移,导致扫描端收不到包。后来我统一用BALANCED模式,兼顾功耗和稳定性。
// 我个人习惯这样配置AdvertiseSettings
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
.setConnectable(true)
.setTimeout(0) // 持续广播
.build();
7.2 AdvertiseData:广播的“内容层”设计
AdvertiseData决定你的广播包里装什么内容。BLE广播包最大只有31字节,非常珍贵。你得精打细算,把最重要的信息放进去。
广播数据通常包含:
- Service UUID:告诉别人你支持什么服务
- Local Name:设备名称(可选,但建议放)
- Manufacturer Specific Data:厂商自定义数据
- Service Data:服务相关数据
注意:Android 8.0(API 26)开始,后台应用不能扫描或广播。如果你的App target API 26+,必须在前台服务中执行广播,否则会静默失败。我曾经踩过这个坑,调试了一整天才发现是后台限制。
// 配置广播数据
AdvertiseData data = new AdvertiseData.Builder()
.addServiceUuid(new ParcelUuid(UUID.fromString("0000FFE0-0000-1000-8000-00805F9B34FB")))
.setIncludeDeviceName(true) // 包含设备名称
.addManufacturerData(0x1234, new byte[]{0x01, 0x02}) // 厂商自定义数据
.build();
7.3 广播回调:监听广播生命周期
广播不是发出去就完事了。你得监听它的状态:开始成功了吗?失败了吗?被停止了?
private AdvertiseCallback callback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
// 广播启动成功
// settingsInEffect 是实际生效的设置,可能与传入的不同
}
@Override
public void onStartFailure(int errorCode) {
// 广播启动失败
switch (errorCode) {
case ADVERTISE_FAILED_ALREADY_STARTED:
// 已经在广播了
break;
case ADVERTISE_FAILED_DATA_TOO_LARGE:
// 广播数据超过31字节
break;
case ADVERTISE_FAILED_FEATURE_UNSUPPORTED:
// 硬件不支持
break;
case ADVERTISE_FAILED_INTERNAL_ERROR:
// 内部错误
break;
case ADVERTISE_FAILED_TOO_MANY_ADVERTISERS:
// 广播者太多(Android 8+限制)
break;
}
}
};
避坑指南:我曾经遇到ADVERTISE_FAILED_TOO_MANY_ADVERTISERS错误。原因是系统限制了同时广播的应用数量(通常只有1-2个)。解决方案是:先停止其他广播,或者使用扩展广播(5.0+)。
7.4 兼容性处理:Android 8+的限制
Android 8.0(API 26)引入了很多后台限制,BLE广播也受影响。具体来说:
- 后台应用不能启动广播:必须在前台服务中执行
- 广播数量限制:系统限制同时广播的应用数量
- 扫描限制:后台应用扫描频率被大幅降低
嗯,这里要注意。如果你的App需要长时间广播,必须启动一个前台服务,并显示通知。否则,广播会在几秒后被系统自动停止。
// Android 8+ 必须在前台服务中启动广播
public class BleForegroundService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 创建通知
Notification notification = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("BLE广播中")
.setContentText("设备正在广播")
.build();
startForeground(1, notification);
// 启动广播
startAdvertising();
return START_STICKY;
}
}
7.5 扩展广播:5.0+的新特性
Android 5.0(API 21)引入了BLE扩展广播(Extended Advertising)。它解决了传统广播的两个痛点:
- 数据容量更大:从31字节扩展到251字节(甚至更多)
- 广播间隔更灵活:支持更长的广播间隔,降低功耗
为什么会这样?因为传统广播的31字节限制,在物联网场景下根本不够用。比如你要广播温度、湿度、气压三个数据,31字节就捉襟见肘了。
扩展广播的使用方式略有不同:
// 扩展广播需要检查硬件支持
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter.isLeExtendedAdvertisingSupported()) {
// 使用扩展广播
AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder()
.setPrimaryPhy(BluetoothDevice.PHY_LE_1M)
.setSecondaryPhy(BluetoothDevice.PHY_LE_2M)
.setInterval(100) // 100ms间隔
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
.build();
// 扩展广播数据可以更大
AdvertiseData data = new AdvertiseData.Builder()
.addServiceUuid(new ParcelUuid(UUID.fromString("0000FFE0-0000-1000-8000-00805F9B34FB")))
.setIncludeDeviceName(true)
.addManufacturerData(0x1234, new byte[200]) // 200字节自定义数据
.build();
} else {
// 回退到传统广播
Log.w("BLE", "设备不支持扩展广播,使用传统广播");
}
个人经验:扩展广播虽然好,但兼容性是个问题。很多低端手机(尤其是2018年前的)不支持。我建议的做法是:先检测是否支持扩展广播,如果不支持就回退到传统广播。这样既能享受新特性,又不会让老设备用户无法使用。
7.6 知识体系总览
下面这张图总结了BLE广播的核心知识点,你可以把它当作开发时的快速参考:
这张图把广播配置、兼容性处理和扩展广播三个核心模块串起来了。你开发时,可以对照这张图检查自己是否遗漏了某个环节。
最后一个小技巧:调试广播时,我建议用nRF Connect这类工具来扫描,能直观看到广播包的内容。我曾经用它发现自己的广播数据里多了一个空字段,排查了好久才发现是Builder的调用顺序问题。