android BLE Peripheral 模拟 ibeacon 发出ble 广播
Android对外模模式(peripheral)的支持:
从Android 5.0+开始才支持。 api level >= 21
所以5.0 之前设备,是不能向外发送广播的。
Android中心设备(central)的支持:
从Android 4.3+ 。 api level >= 18
1、初始化蓝牙
2、检查ble是否可用
3、开启广播
4、扫描响应数据
5、创建iBeacon 广播数据
6、广播设置
7、开启广播后的回调
(1)初始化蓝牙:
添加权限:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- 6.0之后蓝牙还需要地理位置权限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 自行判断 -->
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="false" />
初始化:
//初始化BluetoothManager和BluetoothAdapter
if (mBluetoothManager == null) {
mBluetoothManager = (BluetoothManager) mContext.getSystemService(BLUETOOTH_SERVICE);
} if (mBluetoothManager != null && mBluetoothAdapter == null) {
mBluetoothAdapter = mBluetoothManager.getAdapter();
}
(2)检查是否可使用ble:
if (!activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(activity, "不支持ble", Toast.LENGTH_LONG).show(); return;
}
final BluetoothManager mBluetoothManager = (BluetoothManager) activity.getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
if (mBluetoothAdapter == null) {
Toast.makeText(activity, "不支持ble", Toast.LENGTH_LONG).show(); return;
}
// 获取蓝牙ble广播
16 mBluetoothAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
if (mBluetoothAdvertiser == null) {
Toast.makeText(activity, "the device not support peripheral", Toast.LENGTH_SHORT).show();
Log.e(TAG, "the device not support peripheral"); return;
}
(3)开启广播:
public void startAdvertising(MockServerCallBack callBack) {
//获取BluetoothLeAdvertiser,BLE发送BLE广播用的一个API
if (mBluetoothAdvertiser == null) {
mBluetoothAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
}
if (mBluetoothAdvertiser != null) {try {
//创建BLE beacon Advertising并且广播
mBluetoothAdvertiser.startAdvertising(createAdvSettings(true, 0)
, createIBeaconAdvertiseData(BluetoothUUID.bleServerUUID,
mMajor, mMinor, mTxPower)
, createScanAdvertiseData(mMajor, mMinor, mTxPower, mAdvCallback);
} catch (Exception e) {
Log.v(TAG, "Fail to setup BleService");
}
}
}
一个ble广播包:广播数据其实包含两部分:Advertising Data(广播数据) 和 Scan Response Data(扫描响应数据)。
通常情况下,广播的一方,按照一定的间隔,往空中广播 Advertising Data。
当某个监听设备监听到这个广播数据时候,会通过发送 Scan Response Request,请求广播方发送扫描响应数据数据。
这两部分数据的长度都是固定的 31 字节。
在 Android 中,系统会把这两个数据拼接在一起,返回一个 62 字节的数组。
(4)扫描响应数据:
可以自定义数据,比如增加湿度,温度等。
//设置scan广播数据
public static AdvertiseData createScanAdvertiseData(short major, short minor, byte txPower) {
AdvertiseData.Builder builder = new AdvertiseData.Builder();
builder.setIncludeDeviceName(true); byte[] serverData = new byte[5];
ByteBuffer bb = ByteBuffer.wrap(serverData);
bb.order(ByteOrder.BIG_ENDIAN);
bb.putShort(major);
bb.putShort(minor);
bb.put(txPower);
builder.addServiceData(ParcelUuid.fromString(BluetoothUUID.bleServerUUID.toString())
, serverData); AdvertiseData adv = builder.build();
return adv;
}
5、创建ibeacon 广播数据。
iBeacon 的广播结构:iBeacon 只是协议.
- the 2 byte beacon identifier (0xBEAC)
- the 16 bytes UUID
- the 2 byte major
- the 2 byte minor
- the 1 byte tx power
Byte 0-2: Standard BLE Flags
Byte 0: Length : 0x02
Byte 1: Type: 0x01 (Flags)
Byte 2: Value: 0x06 (Typical Flags)
Byte 3-29: Apple Defined iBeacon Data
Byte 3: Length: 0x1a
Byte 4: Type: 0xff (Custom Manufacturer Packet)
Byte 5-6: Manufacturer ID : 0x4c00 (Apple)
Byte 7: SubType: 0x2 (iBeacon)
Byte 8: SubType Length: 0x15
Byte 9-24: Proximity UUID
Byte 25-26: Major
Byte 27-28: Minor
Byte 29: Signal Power
ManufactureData : 设备厂商的自定义数据
使用addManufactureData(int manufacturerId, byte[] manufacturerSpecificData);
第一个参数0x004c,是厂商id,id长度为2个字节,不足2个字节系统会补0.
(比如id传入0xac, 不足两个字节,输入广播时:ac, 00)
/**
* create AdvertiseDate for iBeacon
*/
public static AdvertiseData createIBeaconAdvertiseData(UUID proximityUuid, short major, short minor, byte txPower) { String[] uuidstr = proximityUuid.toString().replaceAll("-", "").toLowerCase().split("");
byte[] uuidBytes = new byte[16];
for (int i = 1, x = 0; i < uuidstr.length; x++) {
uuidBytes[x] = (byte) ((Integer.parseInt(uuidstr[i++], 16) << 4) | Integer.parseInt(uuidstr[i++], 16));
}
byte[] majorBytes = {(byte) (major >> 8), (byte) (major & 0xff)};
byte[] minorBytes = {(byte) (minor >> 8), (byte) (minor & 0xff)};
byte[] mPowerBytes = {txPower};
byte[] manufacturerData = new byte[0x17];
byte[] flagibeacon = {0x02, 0x15}; System.arraycopy(flagibeacon, 0x0, manufacturerData, 0x0, 0x2);
System.arraycopy(uuidBytes, 0x0, manufacturerData, 0x2, 0x10);
System.arraycopy(majorBytes, 0x0, manufacturerData, 0x12, 0x2);
System.arraycopy(minorBytes, 0x0, manufacturerData, 0x14, 0x2);
System.arraycopy(mPowerBytes, 0x0, manufacturerData, 0x16, 0x1); AdvertiseData.Builder builder = new AdvertiseData.Builder();
builder.addManufacturerData(0x004c, manufacturerData); AdvertiseData adv = builder.build();
return adv;
}
6、创建广播设置:模式,是否可连接,功率
setAdvertiseMode(int advertiseMode)
设置广播的模式,低功耗,平衡和低延迟三种模式;
对应 AdvertiseSettings.ADVERTISE_MODE_LOW_POWER ,ADVERTISE_MODE_BALANCED ,ADVERTISE_MODE_LOW_LATENCY
从左右到右,广播的间隔会越来越短
setConnectable(boolean connectable)
设置是否可以连接。
广播分为可连接广播和不可连接广播,一般不可连接广播应用在iBeacon设备上,这样APP无法连接上iBeacon设备
setTimeout(int timeoutMillis)
设置广播的最长时间,最大值为常量AdvertiseSettings.LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000; 180秒
设为0时,代表无时间限制会一直广播
setTxPowerLevel(int txPowerLevel)
设置广播的信号强度
常量有AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW, ADVERTISE_TX_POWER_LOW, ADVERTISE_TX_POWER_MEDIUM, ADVERTISE_TX_POWER_HIGH
从左到右分别表示强度越来越强.
举例:当设置为ADVERTISE_TX_POWER_ULTRA_LOW时,
手机1和手机2放在一起,手机2扫描到的rssi信号强度为-56左右,
当设置为ADVERTISE_TX_POWER_HIGH 时, 扫描到的信号强度为-33左右,
信号强度越大,表示手机和设备靠的越近
* AdvertiseSettings.ADVERTISE_TX_POWER_HIGH -56 dBm @ 1 meter with Nexus 5
* AdvertiseSettings.ADVERTISE_TX_POWER_LOW -75 dBm @ 1 meter with Nexus 5
* AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM -66 dBm @ 1 meter with Nexus 5
*AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW not detected with Nexus 5
public AdvertiseSettings createAdvSettings(boolean connectable, int timeoutMillis) {
AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder();
//设置广播的模式, 功耗相关
builder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED);
builder.setConnectable(connectable);
builder.setTimeout(timeoutMillis);
builder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
AdvertiseSettings mAdvertiseSettings = builder.build();
if (mAdvertiseSettings == null) {
Log.e(TAG, "mAdvertiseSettings == null");
}
return mAdvertiseSettings;
}
7、开始广播后的回调。提示广播开启是否成功。
//发送广播的回调,onStartSuccess/onStartFailure很明显的两个Callback
private AdvertiseCallback mAdvCallback = new AdvertiseCallback() {
public void onStartSuccess(android.bluetooth.le.AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
if (settingsInEffect != null) {
Log.d(TAG, "onStartSuccess TxPowerLv=" + settingsInEffect.getTxPowerLevel() + " mode=" + settingsInEffect.getMode() + " timeout=" + settingsInEffect.getTimeout());
} else {
Log.d(TAG, "onStartSuccess, settingInEffect is null");
}
} public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
Log.d(TAG, "onStartFailure errorCode=" + errorCode); if (errorCode == ADVERTISE_FAILED_DATA_TOO_LARGE) {
Toast.makeText(mContext, "advertise_failed_data_too_large", Toast.LENGTH_LONG).show();
Log.e(TAG, "Failed to start advertising as the advertise data to be broadcasted is larger than 31 bytes.");
} else if (errorCode == ADVERTISE_FAILED_TOO_MANY_ADVERTISERS) {
Toast.makeText(mContext, "advertise_failed_too_many_advertises", Toast.LENGTH_LONG).show();
Log.e(TAG, "Failed to start advertising because no advertising instance is available."); } else if (errorCode == ADVERTISE_FAILED_ALREADY_STARTED) {
Toast.makeText(mContext, "advertise_failed_already_started", Toast.LENGTH_LONG).show();
Log.e(TAG, "Failed to start advertising as the advertising is already started"); } else if (errorCode == ADVERTISE_FAILED_INTERNAL_ERROR) {
Toast.makeText(mContext, "advertise_failed_internal_error", Toast.LENGTH_LONG).show();
Log.e(TAG, "Operation failed due to an internal error"); } else if (errorCode == ADVERTISE_FAILED_FEATURE_UNSUPPORTED) {
Toast.makeText(mContext, "advertise_failed_feature_unsupported", Toast.LENGTH_LONG).show();
Log.e(TAG, "This feature is not supported on this platform"); }
}
};
注意:对于ios 设备接受广播,外围设备还是要广播出来一个16位的serviceUUID,因为扫描的时候要用(如果不指定特定服务的UUID,没有办法进行后台持续扫描连接).
android BLE Peripheral 模拟 ibeacon 发出ble 广播的更多相关文章
- android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser
android 从4.3系统开始可以连接BLE设备,这个大家都知道了.iOS是从7.0版本开始支持BLE. android 进入5.0时代时,开放了一个新功能,手机可以模拟设备发出BLE广播, 这个新 ...
- android BLE Peripheral 做外设模拟设备,供ios、android 连接通讯。
为了能让其它设备可以发现其设备,先启动特定广播.看自己需要什么广播格式. 对于广播可见的mac address: 在调用startAdvertising();时,mac address 就会改变. 并 ...
- android蓝牙4.0(BLE)开发之ibeacon初步
一个april beacon里携带的信息如下 ? 1 <code class=" hljs ">0201061AFF4C0002159069BDB88C11416BAC ...
- android5.0(Lollipop) BLE Peripheral牛刀小试
转载请表明作者:http://blog.csdn.net/lansefeiyang08/article/details/46468743 知道Android L对蓝牙对了一些改进.包含加入A2dp s ...
- Android 4.4.2上与BLE 蓝牙锁设备的通讯
Android从4.3(Api level 18)开始支持BLE的开发,本文记录了Android 4.4.2设备与BLE设备通讯的流程. 权限需求: <uses-permission andro ...
- Android 6.0 扫描不到 Ble 设备需开启位置权限
Android 6.0 扫描不到 Ble 设备需开启位置权限 之前做 Ble 开发都是在 Android 6.0 系统以下的版本中进行测试的,今天使用 Android 6.0 的设备测试的时候,发现扫 ...
- 详解BLE 空中包格式—兼BLE Link layer协议解析
BLE有几种空中包格式?常见的PDU命令有哪些?PDU和MTU的区别是什么?DLE又是什么?BLE怎么实现重传的?BLE ACK机制原理是什么?希望这篇文章能帮你回答以上问题. 虽然BLE空中包(pa ...
- Android 中的消息传递,详解广播机制
--------------------------------------广播机制简介--------------------------------------------- Android中的广 ...
- Android学习总结(七)———— 本地广播
一.本地广播 2.1 基本概念 由于之前的广播都是全局的,所有应用程序都可以接收到,这样就很容易会引起安全性的问题,比如说我们发送一些携带关键性数据的广播有可能被其他的应用程序截获,或者其他的程序不停 ...
随机推荐
- Linux-Shell编程之判断文件类型
前言 如需使用本博文源码或者撰写文章,请注明博文来源:https://www.cnblogs.com/johnnyzen/p/10534386.html,劳动所得,侵权必究. 题目 設計一個shell ...
- Mybatis-Plus入门
1 Mybatis-Plus简介 1.1 什么是Mybatis-Plus MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化 ...
- Authentication讲解(Spring security认证)
标准认证过程: 1.用户使用username和password登录 2.系统验证这个password对于该username是正确的 3.假设第二步验证成功,获取该用户的上下文信息(如他的角色列表) 4 ...
- python 文本比对
# -*- coding:utf-8 -*- import difflib import sys def readfile(filename): try: fileHandle = open(file ...
- 2018-2019-20175315 实验一 《Java开发环境的熟悉》实验报告
2018-2019-20175315实验一 <Java开发环境的熟悉>实验报告 一.实验内容及步骤 实验1 1.用mkdir建立“20175303exp1”的目录 2.在“20175303 ...
- JUC--ConcurrentHashMap
HashMap HashTable HashTable锁住整个表 会存在复合操作上的问题“若不存则添加” “若存在则删除” 也是不安全的 效率低 ConcurrentHashMap:采用锁分段机制 ...
- nginx unit PHP
2018-12-26 14:20:33 星期三 综述: nginx unit php 的关系: nginx -> 转发请求到 8300端口 -> unit 转发 8300 收到的请求 -& ...
- Oracle_CDC异步Autolog online redo部署示例
一.CDC简介 Oracle CDC (Change Data Capture)变化数据捕获,是一种数据增量处理技术.CDC特性是在Oracle9i数据库中引入的.CDC能够帮助你识别从上次提取之后发 ...
- 先安装VS后安装IIS,注册IIS方法
IIS和VS安装顺序: 最好的顺序是先安装IIS,然后安装VS. 因为在安装VS的时候,安装程序会自动检测计算机上是否安装IIS,若有,则将.NET的当前版本注册到IIS,比如安装VS2010,VS2 ...
- lua post参数获取,参数截断
post 请求头: a.application/x-www-form-urlencoded 普通表单提交 b.multipart/form-data 含有文件的表单,二进制上传 c.applicati ...