Android | BLE | Beacon | 如何廣播的像iBeacon一樣?原生方式與AltBeacon套件
這篇寫於 2021 年。工具和 API 變化很快,部分步驟可能已經不適用。
持續的學習紀錄
封包格式#
020106 :0、1、2,02表示後面數據有2個字元長度,01表示類型為flag,06表示數據。
1AFF :3、4,1A表示接下來的一段數據長度是0x1A=26, 26加上020106這3個長度,再加上1A本身1個長度,剛好是協議上的30字節長度
004C:5與6,廠商ID ,表示蘋果公司。
0215:7與8,類型,表示廣播是iBeacon廣播。
可以解析BLE廣播數據包的第5, 6,7,8字節的數據來判斷這個BLE設備是不是iBeacon設備
1. Java#
private void startAdvertise(String uuid, int major, int minor) {
BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
AdvertiseSettings settings=createAdvertiseSettings(1000);
AdvertiseData data = createAdvertiseData( uuid , major, minor, -59);
//
advertiser.startAdvertising(settings, data, new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
super.onStartSuccess(settingsInEffect);
}
@Override
public void onStartFailure(int errorCode) {
super.onStartFailure(errorCode);
}
});
}
//---------------------------------------------------------------------------------
public AdvertiseSettings createAdvertiseSettings( int timeoutMillis) {
AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder();
builder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY);
builder.setConnectable(true);
builder.setTimeout(timeoutMillis);
builder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
return builder.build();
}
public AdvertiseData createAdvertiseData(String uuidString, int major,
int minor, int txPower) {
AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();
String beaconType = "0215";
String uuid = uuidString.replace("-", "");
String majorStr = formatStringLenth(4, Integer.toHexString(major), '0');
String minorStr = formatStringLenth(4, Integer.toHexString(minor), '0');
String measuredPower = formatStringLenth(2, Integer.toHexString(-59), '0');
//
String dataStr = beaconType + uuid + majorStr + minorStr + measuredPower;
//
byte[] data = hexStringToBytes(dataStr);
mDataBuilder.addManufacturerData(0x004C, data);
AdvertiseData mAdvertiseData = mDataBuilder.build();
return mAdvertiseData;
}
//---------------------------------------------------------------------------------
/**
*
* @param targetLenth 補齊後的長度
* @param src 需要補齊的字串
* @param leftCharacter 用來補齊長度的字元
* @return 補齊字串
*/
public static String formatStringLenth(int targetLenth, String src, char leftCharacter) {
if(src.length()>targetLenth){
return src.substring(src.length()-targetLenth);
}else{
int delta=targetLenth-src.length();
for (int i = 0; i <delta ; i++) {
src=leftCharacter+src;
}
return src;
}
}
/**
* 十六進制字串 轉 字元陣列
* @param hexString "A0B102"
* @return new byte[]{(byte) 0xA0,(byte) 0xB1,2}
*/
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
if(hexString.length()%2!=0){
hexString="0"+hexString;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
2. AltBeacon(Library)#
Beacon beacon = new Beacon.Builder()
.setId1(uuid)
.setId2(major + "")
.setId3(minor + "")
.setManufacturer(0x004C)
.setTxPower(-59)
.setDataFields(Arrays.asList(new Long[]{0l})) // Remove this for beacon layouts without d: fields
.build();
BeaconParser beaconParser = new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24");
BeaconTransmitter beaconTransmitter = new BeaconTransmitter(MyApplication.getInstance(), beaconParser);
beaconTransmitter.setConnectable(true);
beaconTransmitter.startAdvertising(beacon, new AdvertiseCallback() {
@Override
public void onStartFailure(int errorCode) {
KLog.e("Advertisement start failed with code: " + errorCode);
}
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
KLog.i("Advertisement start succeeded.");
}
});
關鍵點:#
setConnectable()需要設為true
最後:#
希望有幫助到你,可以順便給我拍手鼓勵哦 : )
參考#
本文原刊登於 Medium。