You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用开发:修改iBeacon Flags值为0x020106求助

Hey there, let's figure out how to modify the BLE advertising Flags field in your Android app from 0x02011A to 0x020106. First, let's clarify what these values represent to make sure we're on the same page:

  • The Flags field in BLE advertising follows the structure: [Length (1 byte)] [Type (0x01 for Flags)] [Value (1 byte)]
  • 0x02011A means: Length = 0x02, Type = 0x01, Value = 0x1A (LE General Discoverable Mode + BR/EDR Not Supported)
  • 0x020106 means: Length = 0x02, Type = 0x01, Value = 0x06 (LE General Discoverable Mode + BR/EDR Controller Supported but Host Not Supported)

Prerequisites

First, make sure you have the necessary permissions in your AndroidManifest.xml:

<!-- Basic BLE permissions -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!-- For Android 12+ -->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- Location permission required for BLE operations on Android 6.0+ -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />

Don't forget to request runtime permissions for ACCESS_FINE_LOCATION (Android 6.0+) and BLUETOOTH_ADVERTISE (Android 12+).

Implementation Examples

1. Android 8.0 (API 26) and Above

Starting from API 26, Android uses BluetoothLeAdvertiser for more control over BLE advertising. Since the official AdvertiseData.Builder doesn't expose a direct method to set Flags, we'll use reflection to add raw advertising data:

import android.Manifest
import android.bluetooth.BluetoothManager
import android.bluetooth.le.AdvertiseCallback
import android.bluetooth.le.AdvertiseData
import android.bluetooth.le.AdvertiseSettings
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
    private val PERMISSION_REQUEST_CODE = 1001

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Check permissions first
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val requiredPermissions = mutableListOf(Manifest.permission.ACCESS_FINE_LOCATION)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
                requiredPermissions.add(Manifest.permission.BLUETOOTH_ADVERTISE)
                requiredPermissions.add(Manifest.permission.BLUETOOTH_CONNECT)
            }
            if (requiredPermissions.any { checkSelfPermission(it) != PackageManager.PERMISSION_GRANTED }) {
                requestPermissions(requiredPermissions.toTypedArray(), PERMISSION_REQUEST_CODE)
                return
            }
        }

        // Initialize BLE adapter
        val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        val bluetoothAdapter = bluetoothManager.adapter

        // Ensure Bluetooth is enabled
        if (!bluetoothAdapter.isEnabled) {
            Log.e("BLE_ADVERT", "Bluetooth is not enabled")
            // You can request to enable Bluetooth here if needed
            return
        }

        // Build custom advertising data with Flags set to 0x06
        val advertiseDataBuilder = AdvertiseData.Builder()
            .setIncludeDeviceName(false) // Optional: Disable device name to save space
            .setIncludeTxPowerLevel(false) // Optional: Disable TX power level

        // Add custom Flags field using reflection
        try {
            // Raw Flags data: [0x02 (length), 0x01 (type), 0x06 (value)]
            val flagsRawData = byteArrayOf(0x02.toByte(), 0x01.toByte(), 0x06.toByte())
            val addRawDataMethod = AdvertiseData.Builder::class.java.getDeclaredMethod(
                "addRawData", ByteArray::class.java
            )
            addRawDataMethod.isAccessible = true
            addRawDataMethod.invoke(advertiseDataBuilder, flagsRawData)
        } catch (e: Exception) {
            Log.e("BLE_ADVERT", "Failed to add custom Flags: ${e.message}")
        }

        val advertiseData = advertiseDataBuilder.build()

        // Build advertising settings
        val advertiseSettings = AdvertiseSettings.Builder()
            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER)
            .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
            .setConnectable(true)
            .build()

        // Start advertising
        val advertiser = bluetoothAdapter.bluetoothLeAdvertiser
        advertiser.startAdvertising(advertiseSettings, advertiseData, object : AdvertiseCallback() {
            override fun onStartSuccess(settingsInEffect: AdvertiseSettings?) {
                super.onStartSuccess(settingsInEffect)
                Log.d("BLE_ADVERT", "Advertising started successfully! Flags set to 0x06")
            }

            override fun onStartFailure(errorCode: Int) {
                super.onStartFailure(errorCode)
                val errorMsg = when(errorCode) {
                    ADVERTISE_FAILED_ALREADY_STARTED -> "Already advertising"
                    ADVERTISE_FAILED_DATA_TOO_LARGE -> "Advertising data too long (max 31 bytes)"
                    ADVERTISE_FAILED_FEATURE_UNSUPPORTED -> "BLE advertising not supported on this device"
                    ADVERTISE_FAILED_INTERNAL_ERROR -> "Internal error"
                    ADVERTISE_FAILED_TOO_MANY_ADVERTISERS -> "Too many advertisers"
                    else -> "Unknown error: $errorCode"
                }
                Log.e("BLE_ADVERT", "Advertising failed: $errorMsg")
            }
        })
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == PERMISSION_REQUEST_CODE) {
            if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
                // Permissions granted, restart advertising setup
                recreate()
            } else {
                Log.e("BLE_ADVERT", "Required permissions not granted")
            }
        }
    }
}

2. Android 8.0 (API 25) and Below

For older versions, we use BluetoothAdapter.startLeAdvertising() directly, which allows passing raw advertising data:

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseSettings;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    private static final int PERMISSION_REQUEST_CODE = 1001;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Check permissions
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_CODE);
                return;
            }
        }

        // Initialize BLE adapter
        BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();

        if (!bluetoothAdapter.isEnabled()) {
            Log.e("BLE_ADVERT", "Bluetooth is disabled");
            return;
        }

        // Raw advertising data with Flags set to 0x06
        byte[] advertiseData = new byte[]{0x02, 0x01, 0x06};

        // Start advertising
        bluetoothAdapter.startLeAdvertising(null, advertiseData, null, new AdvertiseCallback() {
            @Override
            public void onStartSuccess(AdvertiseSettings settingsInEffect) {
                super.onStartSuccess(settingsInEffect);
                Log.d("BLE_ADVERT", "Advertising started with Flags 0x06");
            }

            @Override
            public void onStartFailure(int errorCode) {
                super.onStartFailure(errorCode);
                Log.e("BLE_ADVERT", "Advertising failed with error code: " + errorCode);
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSION_REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                recreate();
            } else {
                Log.e("BLE_ADVERT", "Location permission required for BLE advertising");
            }
        }
    }
}

Key Notes

  • Data Length Limit: BLE advertising data can't exceed 31 bytes. If you add other fields (like device name or service UUIDs), make sure the total length stays under this limit.
  • System Overrides: Some devices might override your custom Flags if you enable certain settings (like setConnectable(true)). If this happens, try disabling auto-included fields (like device name/TX power) or adjust the reflection approach.
  • Testing: Use nRF Connect to scan for your device and verify the Flags field shows 0x020106.

内容的提问来源于stack exchange,提问作者user9738849

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:03:13