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

startAdvertising 和 startAdvertisingSet 是 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()

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

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui