蓝牙设备分为3种类型:

  • Bluetooth设备(蓝牙BR/EDR):只支持传统蓝牙的设备。
  • Bluetooth Smart Ready 设备(蓝牙4.0双模):同时支持传统蓝牙和LE模式的设备。
  • Bluetooth Smart(BLE单模):只支持LE模式的设备。Beacon设备只支持low energy protocols(LE低功耗协议),因此能靠一颗纽扣电池就能运行很长时间。

BLE起源

BLE 起源于2006年的Nokia的Wibree技术,后被整合进蓝牙,在2010年发布的蓝牙4.0技术规范中成为其中一部分,协议栈入下图所示(它是一组与传统蓝牙不同的协议)

BLE 与传统蓝牙异同点

  • BLE 与传统蓝牙使用的都是相同的波段(2.4GHz - 2.4835GHz)。BLE协议的船速速率比较低,因此除了用于发现设备和做一些简单通信之外,不太适合用于传输大量的数据流。
  • 一台蓝牙设备可同时与其它七台蓝牙设备建立连接
  • 使用跳频频谱扩展技术,把频带分成若干个跳频信道(hop channel),在一次连接中,无线电收发器按一定的码序列不断地从一个信道“跳”到另一个信道
  • 数据传输速率可达1Mbit/s
  • BLE和传统蓝牙信号都能覆盖到100米的范围
  • BLE最大的优势是功耗降低了90%,同时传输距离超过传统蓝牙的100米,安全和稳定性提高(支持AES加密和CRC验证)

iBeacon概述

iBeacon是苹果公司2013年9月发布的移动设备用OS(iOS7)上配备的新功能。其工作方式是,配备有低功耗蓝牙(BLE)通信功能的设备使用BLE技术向周围发送自己特有的ID,接收到该ID的应用软件会根据该ID采取一些行动。

例如:

  • 在店铺里设置iBeacon通信模块的话,便可让iPhone和iPad上运行一资讯告知服务器,或者由服务器向顾客发送折扣券及进店积分。
  • 在家电发生故障或停止工作时使用iBeacon向应用软件发送资讯。
  • 微信的签到就是用iBeacon

iBeacon 的特点

  • 它采用BLE的广播信道传送信号,因此无需配对
  • iBeacon 不具备传统意义上的数据传输功能。因为Beacon基站只推送位置信息,采用的是不可连接模式。
  • 可以通过Beacon基站进行定位,iBeacon本质上是通过rssi来判断设备与基站的距离。

iBeacon 原理

iBeacon中一般有两个角色

  • 基站/从机/外围设备(peripheral),发射端
  • 手机/主机/中心设备(central),接收者

发射端通过BLE的广告通信信道,以一定时间间隔向外广播数据包(Adverting Data,一般是每秒2-3次),每个信号中至少携带了三个主要信息:UUID、Major‘、Minor,这三个信号组成了一个iBeacon的唯一标识符。

当某个监听设备监听到这个广播数据的时候,就好发送 Scan Response Request,请求广播发送方发送扫描响应数据。

这两部分数据的长度都是固定的 31 字节。
在 Android 中,系统会把这两个数据拼接在一起,返回一个 62 字节的数组。

系统支持

  • 外围设备(Peripheral,发射信号)
    Android 5.0+,即 api level >= 21
    iOS7 以上
  • 中心设备(Central,接收信号)
    Android 4.3+,即 api level >= 18

Android 实现 iBeacon 的收发

添加权限

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Android 6.0以后需要添加位置权限,才能搜索的到蓝牙设备 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

检查BLE是否可用

private boolean initBluetooth(Context context) {//判断Android设备是否具有蓝牙特性if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);bluetoothAdapter = bluetoothManager.getAdapter();//获取不到BluetoothAdapter,说明不支持BLEreturn bluetoothAdapter != null;} else {bluetoothAdapter = null;return false;}
}

开始广播

private boolean startAdvertiser() {if(Build.VERSION.SDK_INT < 21) return false;if(!enableBluetooth()) return false;//获取BLE广播bluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();if(bluetoothLeAdvertiser == null) {//设备不支持peripheralreturn false;}String beaconUuid = "fda50693-a4e2-4fb1-afcf-c6eb07647825";//java没有提供16bit的uuid,只有16字节(128bit)的uuid,所以不能设置serviceDataString serviceDataUuid =  "0-0-0-0-4386";String data = "7F7D7D26647D6564807CFEB947FA53745B5097C2b97C3A8363837C";try {bluetoothLeAdvertiser.startAdvertising(createAdvertiseSettings(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY, true, 0, AdvertiseSettings.ADVERTISE_TX_POWER_HIGH),createAdvertiseData(beaconUuid, (short)10028, (short)60350, (byte) -59, serviceDataUuid, data),advertiseCallback);return true;} catch (Exception e) {e.printStackTrace();return false;}}private AdvertiseSettings createAdvertiseSettings(int advertiseMode, boolean connectable, int timeoutMillis, int txPowerLevel) {AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder();//广播模式:低功率、平衡、低延迟builder.setAdvertiseMode(advertiseMode)//是否允许连接.setConnectable(connectable)//默认会广播3分钟(180秒),如果超时时间设置为0,则会取消时间限制.setTimeout(timeoutMillis)//发射功率:极低、低、中、高.setTxPowerLevel(txPowerLevel);return builder.build();}/*** iBeacon 的 ManufacturerData(厂商自定义信息)* 01 byte   type = 0x02 指明它是 iBeacon 帧* 01 byte    len = 0x15 = 21* 16 byte  UUID* 02 byte   major* 02 byte  minor* 01 byte  tx power*/private AdvertiseData createAdvertiseData(String beaconUuidStr, short major, short minor, byte txPower, String serviceDataUuidStr, String serviceData) {//Beacon 标识符byte beaconType = 0x02;//Beacon 厂商自定义信息长度byte beaconLen = 0x15;//Company: Apple, Inc. <0x004C>byte manufacturerId = 0x004c;UUID beaconUuid = UUID.fromString(beaconUuidStr);byte[] manufacturerSpecificData = new byte[23];ByteBuffer bb = ByteBuffer.wrap(manufacturerSpecificData);bb.order(ByteOrder.BIG_ENDIAN);bb.put(beaconType).put(beaconLen).putLong(beaconUuid.getMostSignificantBits()).putLong(beaconUuid.getLeastSignificantBits()).putShort(major).putShort(minor).put(txPower);AdvertiseData.Builder builder = new AdvertiseData.Builder();//广播服务的UUID
//          builder.addServiceUuid(uuid)//添加服务数据UUID和服务数据
//          builder.addServiceData(ParcelUuid.fromString(serviceDataUuidStr), str2bcd(serviceData))//添加制造商ID和数据builder.addManufacturerData(manufacturerId, manufacturerSpecificData)//广播是否包含设备名.setIncludeDeviceName(false)//广播是否包含发射功率等级.setIncludeTxPowerLevel(false);return builder.build();}

停止广播

 private void stopAdvertising() {if(bluetoothLeAdvertiser != null) {bluetoothLeAdvertiser.stopAdvertising(advertiseCallback);}}

下面分析一下 startAdvertising 源码

/**
开启BLE广播。如果操作成功,广播数据将会被广播出去。当设备扫描到这个广播之后,会发送一个扫描请求,请求发送方返回扫描响应数据。该方法调用之后会立即返回,操作的结果通过回调函数分发。* Start Bluetooth LE Advertising. The {@code advertiseData} will be broadcasted if the* operation succeeds. The {@code scanResponse} is returned when a scanning device sends an* active scan request. This method returns immediately, the operation status is delivered* through {@code callback}.* <p>* Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}** @param settings Settings for Bluetooth LE advertising.* @param advertiseData Advertisement data to be advertised in advertisement packet.* @param scanResponse Scan response associated with the advertisement data.* @param callback Callback for advertising status.*/
public void startAdvertising(AdvertiseSettings settings,AdvertiseData advertiseData, AdvertiseData scanResponse,final AdvertiseCallback callback) {synchronized (mLegacyAdvertisers) {
//判断蓝牙状态BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);if (callback == null) {throw new IllegalArgumentException("callback cannot be null");}
//获取周边设备是否可连接boolean isConnectable = settings.isConnectable();
//计算总字节数,    当可连接时,初始3字节。最大数据为31字节if (totalBytes(advertiseData, isConnectable) > MAX_LEGACY_ADVERTISING_DATA_BYTES|| totalBytes(scanResponse, false) > MAX_LEGACY_ADVERTISING_DATA_BYTES) {
//当错误时,通过 new Handler(Looper.getMainLooper()) 主线程的消息循环处理器,将事件在主线程中回调postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE);return;}
//如果start成功,那么callback会被当作键值存储到mLegacyAdvertisers列表中(如果列表已经包含该项,则说明已启动)if (mLegacyAdvertisers.containsKey(callback)) {postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);return;}//Builder模式(建造者模式),属于设计模式中的一种,用来解决构造函数参数太多的问题。Builder模式的代码量会比正常多不少,但是随之带来的好处是代码的可读性和可维护性。但是,往往一个好的设计模式或架构,就是在牺牲某一种能力从而大大增强另一种能力AdvertisingSetParameters.Builder parameters = new AdvertisingSetParameters.Builder();
//当设置为true的时候,会发送符合4.x规范的广播parameters.setLegacyMode(true);parameters.setConnectable(isConnectable);parameters.setScannable(true); // legacy advertisements we support are always scannable
//根据事先定义的常量,配置广播间隔if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) {parameters.setInterval(1600); // 1s} else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_BALANCED) {parameters.setInterval(400); // 250ms} else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) {parameters.setInterval(160); // 100ms}
//根据事先定义的常量,设置信号强度等级if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW) {parameters.setTxPowerLevel(-21);} else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_LOW) {parameters.setTxPowerLevel(-15);} else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) {parameters.setTxPowerLevel(-7);} else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) {parameters.setTxPowerLevel(1);}
//广播间隔,单位10msint duration = 0;int timeoutMillis = settings.getTimeout();if (timeoutMillis > 0) {duration = (timeoutMillis < 10) ? 1 : timeoutMillis / 10;}AdvertisingSetCallback wrapped = wrapOldCallback(callback, settings);
//键是BLE广播操作的回调,值是改变BLE广播设置的回调mLegacyAdvertisers.put(callback, wrapped);
//通过gatt开启广播startAdvertisingSet(parameters.build(), advertiseData, scanResponse, null, null,duration, 0, wrapped);}
}

参数简析

  • AdvertiseSettings settings:广播参数设置

    • int mAdvertiseMode(电量模式)
    • int mAdvertiseTxPowerLevel(信号强度)
    • int mAdvertiseTimeoutMillis(发射间隔)
    • boolean mAdvertiseConnectable(是否允许连接)
  • AdvertiseData advertiseData:外围设备按照一定的时间间隔向空中发送广播包
    • List<ParcelUuid> mManufacturerSpecificData(厂商自定义UUID)
    • Map<ParcelUuid, byte[]> mServiceData(UUID对应的数据)
    • boolean mIncludeTxPowerLevel(是否包含发射信号等级)
    • boolean mIncludeDeviceName(是否包含设备名)
  • AdvertiseData scanResponse:当某个设备监听到这个广播数据的时候,会通过发送Scan Response Request
  • AdvertiseCallback callback: 广播回调函数
    • void onStartSuccess(AdvertiseSettings settingsInEffect)
    • void onStartFailure(int errorCode)

AdvertiseSettings

public final class AdvertiseSettings implements Parcelable {/** 低功耗广播,* Perform Bluetooth LE advertising in low power mode. This is the default and preferred* advertising mode as it consumes the least power.*/public static final int ADVERTISE_MODE_LOW_POWER = 0; /** 性能平衡方式广播* Perform Bluetooth LE advertising in balanced power mode. This is balanced between advertising* frequency and power consumption.*/public static final int ADVERTISE_MODE_BALANCED = 1;/** 低延迟广播* Perform Bluetooth LE advertising in low latency, high power mode. This has the highest power* consumption and should not be used for continuous background advertising.*/public static final int ADVERTISE_MODE_LOW_LATENCY = 2;/** 极低的功率* Advertise using the lowest transmission (TX) power level. Low transmission power can be used* to restrict the visibility range of advertising packets.*/public static final int ADVERTISE_TX_POWER_ULTRA_LOW = 0;/** 低功率* Advertise using low TX power level.*/public static final int ADVERTISE_TX_POWER_LOW = 1;/** 中等功率* Advertise using medium TX power level.*/public static final int ADVERTISE_TX_POWER_MEDIUM = 2;/** 高功率* Advertise using high TX power level. This corresponds to largest visibility range of the* advertising packet.*/public static final int ADVERTISE_TX_POWER_HIGH = 3;/** 最大的广播发送间隔(SIG,Special Interest Group,蓝牙兴趣小组)* The maximum limited advertisement duration as specified by the Bluetooth SIG*/private static final int LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000;

AdvertiseCallback

/**
BLE广播的回调,用来分发广播操作的状态* Bluetooth LE advertising callbacks, used to deliver advertising operation status.*/
public abstract class AdvertiseCallback {/** 广播成功* The requested operation was successful.** @hide*/public static final int ADVERTISE_SUCCESS = 0;/** 广播失败,数据超过了31字节* Failed to start advertising as the advertise data to be broadcasted is larger than 31 bytes.*/public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1;/** 广播失败,无可用的实例* Failed to start advertising because no advertising instance is available.*/public static final int ADVERTISE_FAILED_TOO_MANY_ADVERTISERS = 2;/** 广播已经开启* Failed to start advertising as the advertising is already started.*/public static final int ADVERTISE_FAILED_ALREADY_STARTED = 3;/** 广播失败,由于内部错误* Operation failed due to an internal error.*/public static final int ADVERTISE_FAILED_INTERNAL_ERROR = 4;/** 平台不支持该特性* This feature is not supported on this platform.*/public static final int ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5;

AdvertisingSetCallback

/**
BLE广播设置改变的回调,用来分发广播操作的状态* Bluetooth LE advertising set callbacks, used to deliver advertising operation* status.*/
public abstract class AdvertisingSetCallback {//省略的常量定义和 AdvertiseCallback 一致.../*** Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet}* indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertisingSet* contains the started set and it is advertising. If error occured, advertisingSet is* null, and status will be set to proper error code.** @param advertisingSet The advertising set that was started or null if error.* @param txPower tx power that will be used for this set.* @param status Status of the operation.*/public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) {}/*** Callback triggered in response to {@link BluetoothLeAdvertiser#stopAdvertisingSet}* indicating advertising set is stopped.** @param advertisingSet The advertising set.*/public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {}/*** Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet}* indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertising set is* advertising.** @param advertisingSet The advertising set.* @param status Status of the operation.*/public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable, int status) {}/*** Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating* result of the operation. If status is ADVERTISE_SUCCESS, then data was changed.** @param advertisingSet The advertising set.* @param status Status of the operation.*/public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {}/*** Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating* result of the operation.** @param advertisingSet The advertising set.* @param status Status of the operation.*/public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) {}/*** Callback triggered in response to {@link AdvertisingSet#setAdvertisingParameters}* indicating result of the operation.** @param advertisingSet The advertising set.* @param txPower tx power that will be used for this set.* @param status Status of the operation.*/public void onAdvertisingParametersUpdated(AdvertisingSet advertisingSet,int txPower, int status) {}/*** Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingParameters}* indicating result of the operation.** @param advertisingSet The advertising set.* @param status Status of the operation.*/public void onPeriodicAdvertisingParametersUpdated(AdvertisingSet advertisingSet, int status) {}/*** Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingData}* indicating result of the operation.** @param advertisingSet The advertising set.* @param status Status of the operation.*/public void onPeriodicAdvertisingDataSet(AdvertisingSet advertisingSet,int status) {}/**
advertisingSet.setPeriodicAdvertisingEnabled返回void,它通过调用mGatt.setPeriodicAdvertisingEnabled(mAdvertiserId, enable)异步设置是否启用,然后通过回调函数返回* Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingEnabled}* indicating result of the operation.** @param advertisingSet The advertising set.* @param status Status of the operation.*/public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,int status) {}/**
advertisingSet.getOwnAddress返回void,它通过调用mGatt.getOwnAddress(mAdvertiserId)异步获取地址,获取到之后,通过回调函数返回* Callback triggered in response to {@link AdvertisingSet#getOwnAddress()}* indicating result of the operation.** @param advertisingSet The advertising set.* @param addressType type of address.* @param address advertising set bluetooth address.* @hide*/public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType, String address) {}
}

接收广播

(略)

测试工具推荐

nRF Connect
https://connect.nrf.com/

完整代码

public class MainActivity extends Activity {private static final int REQUEST_ENABLE_BT = 1001;private TextView textview;private BluetoothAdapter bluetoothAdapter;private BluetoothLeAdvertiser bluetoothLeAdvertiser; private AdvertiseCallback advertiseCallback = new AdvertiseCallback() {@Overridepublic void onStartSuccess(AdvertiseSettings settingsInEffect) {//开启广播成功的回调textview.setText("微信摇一摇开启成功");}@Overridepublic void onStartFailure(int errorCode) {//开启广播失败的回调textview.setText("微信摇一摇开启失败," + errorCode);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textview = findViewById(R.id.textview);textview.setText("需要安卓5.0及以上的手机才能使用该功能");startAdvertiser();}@Overrideprotected void onDestroy() {super.onDestroy();stopAdvertising();}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if(requestCode == REQUEST_ENABLE_BT) {if(resultCode == Activity.RESULT_OK) {startAdvertiser();} else {textview.setText("不打开蓝牙无法使用微信摇一摇");}}}private boolean enableBluetooth() {bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);return false;}return true;}private void stopAdvertising() {if(bluetoothLeAdvertiser != null) {bluetoothLeAdvertiser.stopAdvertising(advertiseCallback);}}private boolean startAdvertiser() {if(Build.VERSION.SDK_INT < 21) return false;if(!enableBluetooth()) return false;//获取BLE广播bluetoothLeAdvertiser = bluetoothAdapter.getBluetoothLeAdvertiser();if(bluetoothLeAdvertiser == null) {//设备不支持peripheralreturn false;}String beaconUuid = "fda50693-a4e2-4fb1-afcf-c6eb07647825";//java没有提供16bit的uuid,只有16字节(128bit)的uuid,所以不能设置serviceDataString serviceDataUuid =  "0-0-0-0-4386";String data = "7F7D7D26647D6564807CFEB947FA53745B5097C2b97C3A8363837C";try {bluetoothLeAdvertiser.startAdvertising(createAdvertiseSettings(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY, true, 0, AdvertiseSettings.ADVERTISE_TX_POWER_HIGH),createAdvertiseData(beaconUuid, (short)10028, (short)60350, (byte) -59, serviceDataUuid, data),advertiseCallback);return true;} catch (Exception e) {e.printStackTrace();return false;}}private AdvertiseSettings createAdvertiseSettings(int advertiseMode, boolean connectable, int timeoutMillis, int txPowerLevel) {AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder();//广播模式:低功率、平衡、低延迟builder.setAdvertiseMode(advertiseMode)//是否允许连接.setConnectable(connectable)//默认会广播3分钟(180秒),如果超时时间设置为0,则会取消时间限制.setTimeout(timeoutMillis)//发射功率:极低、低、中、高.setTxPowerLevel(txPowerLevel);return builder.build();}/*** iBeacon 的 ManufacturerData(厂商自定义信息)* 01 byte   type = 0x02 指明它是 iBeacon 帧* 01 byte    len = 0x15 = 21* 16 byte  UUID* 02 byte   major* 02 byte  minor* 01 byte  tx power*/private AdvertiseData createAdvertiseData(String beaconUuidStr, short major, short minor, byte txPower, String serviceDataUuidStr, String serviceData) {//Beacon 标识符byte beaconType = 0x02;//Beacon 厂商自定义信息长度byte beaconLen = 0x15;//Company: Apple, Inc. <0x004C>byte manufacturerId = 0x004c;UUID beaconUuid = UUID.fromString(beaconUuidStr);byte[] manufacturerSpecificData = new byte[23];ByteBuffer bb = ByteBuffer.wrap(manufacturerSpecificData);bb.order(ByteOrder.BIG_ENDIAN);bb.put(beaconType).put(beaconLen).putLong(beaconUuid.getMostSignificantBits()).putLong(beaconUuid.getLeastSignificantBits()).putShort(major).putShort(minor).put(txPower);AdvertiseData.Builder builder = new AdvertiseData.Builder();//广播服务的UUID
//          builder.addServiceUuid(uuid)//添加服务数据UUID和服务数据
//          builder.addServiceData(ParcelUuid.fromString(serviceDataUuidStr), str2bcd(serviceData))//添加制造商ID和数据builder.addManufacturerData(manufacturerId, manufacturerSpecificData)//广播是否包含设备名.setIncludeDeviceName(false)//广播是否包含发射功率等级.setIncludeTxPowerLevel(false);return builder.build();}public static String bcd2Str(byte[] bytes) {StringBuffer temp = new StringBuffer(bytes.length * 2);for (int i = 0; i < bytes.length; i++) {temp.append((byte) ((bytes[i] & 0xf0) >>> 4));temp.append((byte) (bytes[i] & 0x0f));}return temp.toString();}public static byte [] str2bcd(String s){if(s.length () % 2 != 0) {s = "0" + s;}ByteArrayOutputStream baos = new ByteArrayOutputStream ();char [] cs = s.toCharArray ();for (int i = 0; i < cs.length; i += 2){int high = cs [i] - 48;int low = cs [i + 1] - 48;baos.write (high << 4 | low);}return baos.toByteArray ();}}

以上测试代码主要用来模拟本公司微信签到的 iBeacon,实测可用。
但是 ParcelUUID 和 UUID都只提供了128-bit 的构造方法(内部都是两个long实现的),没有找到 16bit 的构造方法,所以 ServiceData 模拟不出来!!!

Android 实现 iBeacon相关推荐

  1. 前Vertu设计师推出Android版iBeacon,无需专有硬件,没话费的旧手机都能做基站

    黑太一 • 2014-01-21 11:24 文章摘要:iBeacon技术被许多人看好,今年可能会大规模铺开,在室内营销.精准推广方面会有很大改观.近日,前Vertu设计师Nuovo推出一款新产品Da ...

  2. Android BLE开发之Android手机搜索iBeacon基站

    本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处! 上次讲了Android手机与BLE终端之间的通信,而最常见的BLE终端应该是苹果公司倡导的iBeacon基站. ...

  3. android ibeacon sdk,智慧通行SDK

    智慧通行SDK 2017年12月 1.引言 1.1.编写之前 本文档为第三方APP提供了接入特斯联通行SDK的能力,使第三方APP具有智能通行.电子钥匙.访客管理等功能. SDK包含如下功能: 登录 ...

  4. Beacon室内导航方案资料汇总(Android)

    Beacon室内导航方案资料汇总(Android) 最近在做基于beacon的室内导航,找了点资料做个记录也顺便分享一下: 一.Beacon文档汇总 开发ibeacon定位APP5大技术亮点地址 ht ...

  5. android蓝牙4.0(BLE)开发之ibeacon初步

    一个april beacon里携带的信息如下 ? 1 <code class=" hljs ">0201061AFF4C0002159069BDB88C11416BAC ...

  6. Android Beacon 开发(IBeacon)

    iBeacon是苹果公司2013年9月发布的移动设备用OS(ios7)上配备的新功能.其主要的工作方式就是:配备有低功耗蓝牙 (BLE)通信功能的设备使用BLE技术向周围发送自己特有的ID. 这个网址 ...

  7. 【Android IBeacon室内定位】Android Beacon Library之搜索最近的beacon

    1.了解IBeacon ibeacon是苹果公司于2013年提出的低功耗蓝牙(BLE)传输技术,可以实现室内定位,关于Ibeacon的介绍.使用原理和原始的开发方式网上已经有很多相关的资料了,可以查看 ...

  8. android BLE Peripheral 模拟 ibeacon 发出ble 广播

    原文地址: https://www.cnblogs.com/CharlesGrant/p/7155211.html Android对外模模式(peripheral)的支持: 从Android 5.0+ ...

  9. android beacon微定位,【iBeacon定位开发】- AndroidBLE--Measuring distance(测量距离)

    Measuring distance(测量距离) TX power ,用于确定你和beacon之间距离有多近.根据这个值不但可以获得粗略的信息(比如靠近/远离/不在范围内等),也可以获取精确到米的距离 ...

  10. Android开发:IBeacon系列——安卓蓝牙4.0(BLE)开发之检测IBeacon热点初步

    检测ibeacon热点信号 软硬件要求:Android4.3及以上中支持BLE技术,同时蓝牙需要满足Bluetooth4.0及以上. iBeacon的工作原理是基于Bluetooth Low Ener ...

最新文章

  1. windows 下更新 npm 和 node
  2. 域名系统DNS、文件传送协议FTP、动态主机配置协议DHCP、远程登录协议TELNET、电子邮件协议(SMTP/POP3/IMAP)、常用端口
  3. Spirng使用Aspectj实现AOP
  4. php7.0支持调用lua脚本
  5. 中科大计算机考研录取分数线_中科大计算机考研 | 跨考CS上岸经验分享!
  6. http抓包实践--(一)--fiddler和http(s)
  7. 《麦肯锡方法》学习笔记18
  8. linux桌面图标主题包,推荐 4 款漂亮的 Linux 图标主题
  9. Unity3D IAP Google支付
  10. java的time_Java TimeUnit使用
  11. c++读取cfg文件
  12. 重装系统(win7)
  13. 计算机输入法无法启动,win7电脑开机没有输入法怎么办?
  14. MySql数据库简介(一)
  15. python爬虫-源码
  16. 基于51单片机的智能家居安防系统(程序+仿真+PCB)
  17. 竞争优势究竟是什么?
  18. ThinkPHP中实现微信支付(jsapi支付)流程
  19. Spring Bean的自动装配方式
  20. C. 小票输入输出(结构体)

热门文章

  1. Spark多版本共存
  2. 汇编语言 大小比较 理解 ja jna jg jle
  3. 【第一组】第十三次例会纪要
  4. StarUML使用心得
  5. HBase BulkLoad批量写入数据实战
  6. 手机型号云服务器,手机型号云服务器
  7. [ERROR NumCPU]: the number of available CPUs 1 is less than the required 2
  8. 运输小猫(斜率优化)
  9. 11.4王者荣耀服务器维护中,4月11日全服不停机更新公告
  10. 原生js + canvas 实现刻度尺效果