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 的超集,提供了更多高级功能,特别适合需要传输大量数据或需要精细控制广告行为的应用场景。

相关推荐
雪球Snowball2 小时前
【Android关键流程】Configuration变更时更新应用程序配置
android
h7ml2 小时前
于 CompletableFuture 的异步编排优化企业微信通知发送性能
android·windows·企业微信
子木鑫2 小时前
[SUCTF 2019] CheckIn1 — 利用 .user.ini 与图片马构造 PHP 后门并绕过上传检测
android·开发语言·安全·php
风清云淡_A2 小时前
【ANDROID】使用webview实现加载第三方的网页效果
android
吴声子夜歌2 小时前
RxJava——操作符详解(四)
android·echarts·rxjava
我是阿亮啊3 小时前
Android Handler 消息机制之 Looper 深度解析
android·loop·handler·looper
Mr YiRan3 小时前
Android 16KB 腾讯Mars XLog适配
android
2501_915921433 小时前
不用 Xcode 上架 iOS,拆分流程多工具协作完成 iOS 应用的发布准备与提交流程
android·macos·ios·小程序·uni-app·iphone·xcode
子木鑫3 小时前
[SUCTF2019 & GXYCTF2019] 文件上传绕过实战:图片马 + .user.ini / .htaccess 构造 PHP 后门
android·开发语言·安全·php