最近在做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的一些心得,如有不足之处,欢迎指导~