iBeacon

蓝牙设备分为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技术规范中成为其中一部分,协议栈入下图所示(它是一组与传统蓝牙不同的协议)

iBeacon

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,说明不支持BLE
		return 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) {
	        //设备不支持peripheral
	        return false;
	    }
	    String beaconUuid = "fda50693-a4e2-4fb1-afcf-c6eb07647825";
	    //java没有提供16bit的uuid,只有16字节(128bit)的uuid,所以不能设置serviceData
		String 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);
		}
//广播间隔,单位10ms
		int 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() {
		@Override
		public void onStartSuccess(AdvertiseSettings settingsInEffect) {
			//开启广播成功的回调
			textview.setText("微信摇一摇开启成功");
		}
		@Override
		public void onStartFailure(int errorCode) {
			//开启广播失败的回调
			textview.setText("微信摇一摇开启失败," + errorCode);
		}
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		textview = findViewById(R.id.textview);
		textview.setText("需要安卓5.0及以上的手机才能使用该功能");
		startAdvertiser();
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		stopAdvertising();
	}

	@Override
	protected 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) {
	        //设备不支持peripheral
	        return false;
	    }
	    String beaconUuid = "fda50693-a4e2-4fb1-afcf-c6eb07647825";
	    //java没有提供16bit的uuid,只有16字节(128bit)的uuid,所以不能设置serviceData
		String 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 模拟不出来!!!

iBeacon