android-蓝牙-广播启动-startAdvertising和startAdvertisingSet区别

startAdvertisingstartAdvertisingSet 是 Android BLE API 中用于启动蓝牙广告的两个方法,它们的主要区别在于 功能和能力startAdvertisingSet 是 Android 8.0 (API 26) 引入的更强大的广告方法,支持 Bluetooth 5.0 的新特性。

主要区别概览

特性 startAdvertising startAdvertisingSet
引入版本 Android 5.0 (API 21) Android 8.0 (API 26)
Bluetooth 版本 4.x 5.0+
广告类型 标准广告 (最多31字节) 扩展广告 (最多1650字节)
同时广播 只能一个广告 多个广告集同时广播
周期广告 不支持 支持
控制粒度 简单控制 精细控制,可动态修改
回调对象 AdvertiseCallback AdvertisingSetCallback

详细对比

1. startAdvertising - 传统广告方法

这是最基本的BLE广告方法,功能相对简单。

java 复制代码
// 传统广告方法签名
void startAdvertising(
    AdvertiseSettings settings,
    AdvertiseData advertiseData,
    AdvertiseData scanResponse,
    AdvertiseCallback callback
)

// 使用示例
bluetoothLeAdvertiser.startAdvertising(
    settings,
    advertiseData,
    scanResponse,
    new AdvertiseCallback() {
        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            // 广告启动成功
        }
        
        @Override
        public void onStartFailure(int errorCode) {
            // 广告启动失败
        }
    }
);

限制

  • 只能广播最多 31 字节数据
  • 一次只能启动一个广告实例
  • 不能动态修改广告参数
  • 不支持周期广告

2. startAdvertisingSet - 扩展广告方法

这是更强大的广告方法,支持 Bluetooth 5.0 的新特性。

java 复制代码
// 扩展广告方法签名
void startAdvertisingSet(
    AdvertisingSetParameters parameters,
    AdvertiseData advertiseData,
    AdvertiseData scanResponse,
    PeriodicAdvertisingParameters periodicParameters,
    AdvertiseData periodicData,
    AdvertisingSetCallback callback
)

// 可选参数形式
void startAdvertisingSet(
    AdvertisingSetParameters parameters,
    AdvertiseData advertiseData,
    AdvertiseData scanResponse,
    PeriodicAdvertisingParameters periodicParameters,
    AdvertiseData periodicData,
    int duration,
    int maxExtendedAdvertisingEvents,
    AdvertisingSetCallback callback
)

功能对比详解

示例对比

传统广告 (startAdvertising)
java 复制代码
public void startTraditionalAdvertising() {
    // 传统广告设置
    AdvertiseSettings settings = new AdvertiseSettings.Builder()
            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
            .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
            .setConnectable(true)
            .setTimeout(0)
            .build();
    
    // 广告数据(最多31字节)
    AdvertiseData advertiseData = new AdvertiseData.Builder()
            .setIncludeDeviceName(true)
            .addServiceUuid(new ParcelUuid(SERVICE_UUID))
            .addManufacturerData(0x004C, new byte[]{0x01, 0x02}) // 最多31字节
            .build();
    
    bluetoothLeAdvertiser.startAdvertising(settings, advertiseData, null, callback);
}
扩展广告 (startAdvertisingSet)
java 复制代码
public void startExtendedAdvertisingSet() {
    // 1. 创建广告集参数(支持更多配置选项)
    AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder()
            .setLegacyMode(false) // 使用扩展广告模式
            .setConnectable(true)
            .setScannable(true)
            .setInterval(AdvertisingSetParameters.INTERVAL_MIN) // 广告间隔
            .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_MAX) // 发射功率
            .setPrimaryPhy(BluetoothDevice.PHY_LE_1M) // 主要PHY
            .setSecondaryPhy(BluetoothDevice.PHY_LE_2M) // 次要PHY
            .build();
    
    // 2. 广告数据(支持最多1650字节)
    AdvertiseData advertiseData = new AdvertiseData.Builder()
            .setIncludeDeviceName(true)
            .addServiceUuid(new ParcelUuid(SERVICE_UUID))
            .addServiceData(new ParcelUuid(SERVICE_UUID), largePayload) // 可以传输大量数据
            .build();
    
    // 3. 周期广告参数(可选)
    PeriodicAdvertisingParameters periodicParameters = new PeriodicAdvertisingParameters.Builder()
            .setIncludeTxPower(true)
            .setInterval(PeriodicAdvertisingParameters.INTERVAL_MIN)
            .build();
    
    // 4. 周期广告数据
    AdvertiseData periodicData = new AdvertiseData.Builder()
            .addServiceData(new ParcelUuid(SERVICE_UUID), periodicPayload)
            .build();
    
    // 5. 启动广告集
    bluetoothLeAdvertiser.startAdvertisingSet(
            parameters,
            advertiseData,
            null, // 扫描响应
            periodicParameters,
            periodicData,
            callback
    );
}

关键特性详解

1. 扩展广告 (Extended Advertising)

java 复制代码
// 启用扩展广告
AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder()
        .setLegacyMode(false) // false = 扩展广告,true = 传统广告
        .setPrimaryPhy(BluetoothDevice.PHY_LE_1M)
        .setSecondaryPhy(BluetoothDevice.PHY_LE_2M)
        .build();

// 优势:
// - 广告数据最多1650字节(传统只有31字节)
// - 支持2M PHY,速率更快
// - 可以在不同PHY上同时广播

2. 周期广告 (Periodic Advertising)

java 复制代码
// 配置周期广告
PeriodicAdvertisingParameters periodicParams = new PeriodicAdvertisingParameters.Builder()
        .setIncludeTxPower(true)
        .setInterval(PeriodicAdvertisingParameters.INTERVAL_MIN) // 7.5ms - 81.91875s
        .build();

// 优势:
// - 扫描设备可以同步到周期广告
// - 减少扫描功耗
// - 适合发送不频繁变化的数据

3. 多个广告集同时运行

java 复制代码
// 可以同时启动多个广告集
private List<AdvertisingSet> advertisingSets = new ArrayList<>();

public void startMultipleAdvertisingSets() {
    // 第一个广告集
    AdvertisingSetParameters params1 = new AdvertisingSetParameters.Builder()
            .setLegacyMode(true)
            .setConnectable(true)
            .build();
    
    // 第二个广告集
    AdvertisingSetParameters params2 = new AdvertisingSetParameters.Builder()
            .setLegacyMode(false)
            .setConnectable(false)
            .build();
    
    // 同时启动两个广告集
    bluetoothLeAdvertiser.startAdvertisingSet(params1, data1, null, null, null, callback1);
    bluetoothLeAdvertiser.startAdvertisingSet(params2, data2, null, null, null, callback2);
}

4. 动态广告控制

java 复制代码
AdvertisingSetCallback callback = new AdvertisingSetCallback() {
    @Override
    public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) {
        if (status == AdvertisingSetCallback.ADVERTISE_SUCCESS) {
            // 1. 动态修改广告数据
            advertisingSet.setAdvertisingData(newAdvertiseData);
            
            // 2. 修改扫描响应数据
            advertisingSet.setScanResponseData(newScanResponseData);
            
            // 3. 修改广告参数
            advertisingSet.setAdvertisingParameters(newParameters);
            
            // 4. 启用/禁用广告
            advertisingSet.enableAdvertising(true, duration, maxEvents);
            
            // 5. 周期广告控制
            advertisingSet.setPeriodicAdvertisingData(periodicData);
            advertisingSet.setPeriodicAdvertisingParameters(periodicParams);
            advertisingSet.enablePeriodicAdvertising(true);
        }
    }
};

完整使用示例

java 复制代码
public class ExtendedAdvertiser {
    private BluetoothLeAdvertiser advertiser;
    private AdvertisingSet currentAdvertisingSet;
    
    public void startExtendedAdvertising() {
        // 1. 检查是否支持扩展广告
        if (!BluetoothAdapter.getDefaultAdapter().isLeExtendedAdvertisingSupported()) {
            Log.w("BLE", "设备不支持扩展广告,使用传统广告");
            startTraditionalAdvertising();
            return;
        }
        
        // 2. 配置扩展广告参数
        AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder()
                .setLegacyMode(false) // 扩展广告
                .setConnectable(true)
                .setScannable(true)
                .setInterval(AdvertisingSetParameters.INTERVAL_MIN)
                .setTxPowerLevel(AdvertisingSetParameters.TX_POWER_HIGH)
                .setPrimaryPhy(BluetoothDevice.PHY_LE_1M)
                .setSecondaryPhy(BluetoothDevice.PHY_LE_2M)
                .build();
        
        // 3. 准备大容量广告数据(超过31字节)
        byte[] largePayload = new byte[500];
        // ... 填充数据
        
        AdvertiseData advertiseData = new AdvertiseData.Builder()
                .setIncludeDeviceName(true)
                .setIncludeTxPowerLevel(true)
                .addServiceUuid(new ParcelUuid(SERVICE_UUID))
                .addServiceData(new ParcelUuid(SERVICE_UUID), largePayload)
                .build();
        
        // 4. 配置周期广告
        PeriodicAdvertisingParameters periodicParams = new PeriodicAdvertisingParameters.Builder()
                .setIncludeTxPower(true)
                .setInterval(100) // 单位:1.25ms,所以是125ms
                .build();
        
        AdvertiseData periodicData = new AdvertiseData.Builder()
                .addServiceData(new ParcelUuid(SERVICE_UUID), "Periodic Data".getBytes())
                .build();
        
        // 5. 创建回调
        AdvertisingSetCallback callback = new AdvertisingSetCallback() {
            @Override
            public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, 
                    int txPower, int status) {
                if (status == ADVERTISE_SUCCESS) {
                    currentAdvertisingSet = advertisingSet;
                    Log.i("BLE", "扩展广告启动成功,发射功率:" + txPower + "dBm");
                    
                    // 启用周期广告
                    advertisingSet.enablePeriodicAdvertising(true);
                }
            }
            
            @Override
            public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
                Log.i("BLE", "广告集已停止");
                currentAdvertisingSet = null;
            }
            
            @Override
            public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, 
                    boolean enable, int status) {
                Log.i("BLE", "周期广告" + (enable ? "启用" : "禁用") + ",状态:" + status);
            }
        };
        
        // 6. 启动扩展广告
        advertiser.startAdvertisingSet(
                parameters,
                advertiseData,
                null, // 扫描响应
                periodicParams,
                periodicData,
                callback
        );
    }
    
    public void updateAdvertisingData(byte[] newData) {
        if (currentAdvertisingSet != null) {
            AdvertiseData newAdvertiseData = new AdvertiseData.Builder()
                    .addServiceData(new ParcelUuid(SERVICE_UUID), newData)
                    .build();
            
            currentAdvertisingSet.setAdvertisingData(newAdvertiseData);
        }
    }
    
    public void stopAdvertising() {
        if (currentAdvertisingSet != null) {
            currentAdvertisingSet.stopAdvertising();
            currentAdvertisingSet = null;
        }
    }
}

选择建议

使用 startAdvertising 当:

  • 需要兼容 Android 5.0-7.x 设备
  • 广告数据不超过31字节
  • 只需要基本的广告功能
  • 项目时间/资源有限

使用 startAdvertisingSet 当:

  • 目标设备是 Android 8.0+ 且支持 Bluetooth 5.0
  • 需要传输大量数据(>31字节)
  • 需要周期广告功能
  • 需要同时广播多个服务
  • 需要动态更新广告内容
  • 对功耗有更高要求

兼容性处理示例

java 复制代码
public void startAdvertisingWithFallback() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
            bluetoothAdapter.isLeExtendedAdvertisingSupported()) {
        // 使用扩展广告
        startExtendedAdvertisingSet();
    } else {
        // 降级到传统广告
        startTraditionalAdvertising();
    }
}

注意事项

  1. 权限要求:扩展广告需要 Android 8.0+ 和 Bluetooth 5.0 硬件支持
  2. 功耗考虑:扩展广告和周期广告可能增加功耗
  3. 兼容性:老设备可能无法接收扩展广告
  4. 限制检查 :使用前检查 BluetoothAdapter.isLeExtendedAdvertisingSupported()

总结来说,startAdvertisingSetstartAdvertising 的超集,提供了更多高级功能,特别适合需要传输大量数据或需要精细控制广告行为的应用场景。

相关推荐
城东米粉儿4 分钟前
Android Flow 笔记
android
测试工坊10 分钟前
Android CPU 使用率不准?一文搞懂 DVFS 降频对性能数据的影响
android
城东米粉儿13 分钟前
Android Hilt 笔记
android
醉饮千觞不知愁1 小时前
Android Lifecycle的事件与状态映射关系
android·kotlin
千里马学框架1 小时前
app性能优化:优化布局层次结构
android·面试·性能优化·framework·分屏·布局·小米汽车
dustcell.1 小时前
高性能web服务器
android·服务器·前端
zh_xuan1 小时前
React Native Demo
android·javascript·react native·ts
zh_xuan2 小时前
kotlin 挂起函数2
android·kotlin·挂起函数
kyle~2 小时前
MySQL基础知识点与常用SQL语句整理
android·sql·mysql
XiaoLeisj2 小时前
Android RecyclerView 实战:从基础列表到多类型 Item、分割线与状态复用问题
android·java