当前位置: 首页 > 工具软件 > Beacon > 使用案例 >

android 蓝牙Beacon开发

郤旭东
2023-12-01

最近在做android 蓝牙Beacon开发,记录一下一些个人心得:
1.蓝牙Beacon主要的应用场景:
(1)用于室内定导航,如大型超市、博物馆、机场、校园等;
(2)信息推送(商场活动、景区游览、博物馆展品信息);
(3)和微信摇一摇结合,摇互动、摇签到、摇导航等。

2.蓝牙beacon广播包广播出来的信息包括4个方面:
(1)蓝牙beacon的MAC地址(广播包来自于哪一个 MAC 地址的从机设备);
(2)蓝牙beacon的信号强度RSSI值(扫描者在搜索到此Beacon时的信号强度);
(3)还有广播出来的数据包的内容,该数据包内容最多可以包含 31 个字节的内容(超出会广播失败);
(4)蓝牙beacon的UUID(服务ID,也可以携带数据包内容);

3.android设备硬件要求:
支持蓝牙BLE功能
//判断手机是否支持BLE
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
    Log.i(TAG, "支持BLE");
} else {
    Log.i(TAG, "不支持BLE");
}

4.权限要求:

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

5.判断是否授权定位权限:
这里我使用的权限库是:  implementation 'pub.devrel:easypermissions:1.1.0',实现方法不再赘述。
(1)首先检查权限:

    private String[] perms = { Manifest.permission.ACCESS_FINE_LOCATION};
    private static final int REQUEST_CODE = 0x01;
    private void checkPerms() {
        if(Build.VERSION.SDK_INT>=23){
            if(EasyPermissions.hasPermissions(MainActivity.this,perms)){
                sendBeacon();
            }else {
                EasyPermissions.requestPermissions(MainActivity.this,"需开启定位权限",REQUEST_CODE,perms);
            }
        }else {
            sendBeacon();
        }
    }

(2)打开蓝牙:

    private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
    private BluetoothAdapter bluetoothAdapter;
    private void sendBeacon(){
        BluetoothManager bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
        bluetoothAdapter = bluetoothManager.getAdapter();
        //实际项目需监听蓝牙已开启,再执行后续操作,本demo不做详细阐述,只提供思路
        if(bluetoothAdapter.isEnabled()){  // 判断蓝牙是否可用
            bluetoothAdapter.enable();  // 打开蓝牙
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mBluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
                    startAdvertising();
                }
            },2000);
        }
    }

6.设置广播:
先来了解一下AdvertiseSettings,它主要是设置广播模式,用来控制广播性能及延迟。

6.1 setAdvertiseMode(设置频率):
ADVERTISE_MODE_LOW_LATENCY 100ms (低延迟)
ADVERTISE_MODE_BALANCED  250ms   (平衡模式)
ADVERTISE_MODE_LOW_POWER 1s      (低功耗)

6.2 setTxPowerLevel(设置广播发送功率,由高到低):
ADVERTISE_TX_POWER_HIGH = 3;
ADVERTISE_TX_POWER_MEDIUM = 2;
ADVERTISE_TX_POWER_LOW = 1;
ADVERTISE_TX_POWER_ULTRA_LOW = 0;

6.3 setConnectable(设置广播类型是否可连接)
true:可连接
false:不可连接

6.4 setTimeout(设置广播超时时间):
int型,不得超过180000毫秒;如果设置值为0将禁用时间限制,一直广播;

    private AdvertiseSettings buildAdvertiseSettings() {
        AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
        settingsBuilder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);
        settingsBuilder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
        settingsBuilder.setConnectable(false); // 一般设置不可连接,可根据实际场景设置
        settingsBuilder.setTimeout(0);
        return settingsBuilder.build();
    }

7.设置UUID及数据包:
AdvertiseData方法介绍:
addServiceUuid(ParcelUuid serviceUuid): // 添加服务UUID,也可以通过多次add的方式来组自定义数据包
addServiceData(ParcelUuid serviceDataUuid, byte[] serviceData):  // 添加服务UUID及自定义数据包
addManufacturerData(int manufacturerId, byte[] manufacturerSpecificData):   // 添加制造商特定UUID及自定义数据包
setIncludeTxPowerLevel(boolean includeTxPowerLevel):  // 发送数据包中是否应包括发射功率电平
setIncludeDeviceName(boolean includeDeviceName):       // 是否包含设备名称,尽量不要设置为true,否则会导致可携带的自定义数据包大大减小;
这里几种发送数据包的方式type不同,具体可在接收数据包中查看。

    private final static String Service_UUID = "00001234-0000-1000-8000-00805F9B34FB";
    // 发送自定义数据包
    private AdvertiseData buildAdvertiseData() {
        AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
      //  dataBuilder.setIncludeDeviceName(true); 

        dataBuilder.addServiceUuid(ParcelUuid.fromString(Service_UUID));

        return dataBuilder.build();
    }

8.蓝牙Beacon广播结果回调
这里说一下返回的常见的几种errorCode:

    public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1;   // 常见错误,广播的数据包太大,无法启动广播,检查一下是否有设置dataBuilder.setIncludeDeviceName(true);如果有,改为false;如果未设置,那就是数据包超出了最大长度。
    public static final int ADVERTISE_FAILED_TOO_MANY_ADVERTISERS = 2;// 没有可用的广播实例
    public static final int ADVERTISE_FAILED_ALREADY_STARTED = 3; //广播已经开始,无法开始广播
    public static final int ADVERTISE_FAILED_INTERNAL_ERROR = 4;  // 由于内部错误,操作失败
    public static final int ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5; //该平台不支持此功能
    个人在实际开发的过程中,还遇到过errorCode=7的情况,而出现这种情况是由于sendDatas中的数据包太短,仅供参考。


    public class MyAdvertiseCallback extends AdvertiseCallback {

        private String TAG = getClass().getName();
        @Override
        public void onStartFailure(int errorCode) {
            super.onStartFailure(errorCode);
            Log.i(TAG, "AdvertiseCallback onStartFailure");
        }

        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            super.onStartSuccess(settingsInEffect);
            Log.i(TAG, "AdvertiseCallback onStartSuccess");
        }
    }


9.开始蓝牙广播

    private void startAdvertising() {
        if (mAdvertiseCallback == null) {
            AdvertiseSettings settings = buildAdvertiseSettings();
            AdvertiseData data = buildAdvertiseData();
            mAdvertiseCallback = new MyAdvertiseCallback();
            if (mBluetoothLeAdvertiser != null) {
                if(mAdvertiseCallback != null){
                    mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);  //  如果之前未停止广播,先停止广播
                }
                mBluetoothLeAdvertiser.startAdvertising(settings, data, mAdvertiseCallback);
            }
        }
    }

10.停止广播:

    if (mBluetoothLeAdvertiser != null) {
            mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
    }

这里推荐一款软件-- nRF Connect ,可以接收到蓝牙Beacon包,以验证自己发的包数据。
    
以上即为本人在开发蓝牙Beacon的一些心得,如有不足之处,欢迎指导~    

   
 

 类似资料: