Это рекламодатель (уведомление data
передано как AdvertiseData
)
private void advertise() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothLeAdvertiser advertiser = bluetoothAdapter.getBluetoothLeAdvertiser();
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
.setConnectable(false)
.build();
ParcelUuid pUuid = new ParcelUuid(UUID.fromString("cf2c82b6-6a06-403d-b7e6-13934e602664"));
AdvertiseData data = new AdvertiseData.Builder()
//.setIncludeDeviceName(true)
.addServiceUuid(pUuid)
.addServiceData(pUuid, "123456".getBytes(Charset.forName("UTF-8")))
.build();
AdvertiseCallback advertiseCallback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
Log.i(tag, "Advertising onStartSuccess");
super.onStartSuccess(settingsInEffect);
}
@Override
public void onStartFailure(int errorCode) {
Log.e(tag, "Advertising onStartFailure: " + errorCode);
super.onStartFailure(errorCode);
}
};
advertiser.startAdvertising(settings, data, advertiseCallback);
}
Он начинается успешно.
Это сканер
private void discover() {
ScanSettings settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_BALANCED)
.build();
mBluetoothLeScanner.startScan(null, settings, mScanCallback);
}
private ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
Log.i(tag, "Discovery onScanResult");
if (result == null) {
Log.i(tag, "no result");
return;
}
ScanRecord scanRecord = result.getScanRecord();
List<ParcelUuid> list = scanRecord != null ? scanRecord.getServiceUuids() : null;
if (list != null) {
Log.i(tag, scanRecord.toString());
for (ParcelUuid uuid : list) {
byte[] data = scanRecord.getServiceData(uuid);
}
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
Log.i(tag, "Discovery onBatchScanResults");
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
Log.e(tag, "Discovery onScanFailed: " + errorCode);
}
};
В обратном вызове onScarnResult
я записываю запись сканирования toString()
, которая производит этот вывод
ScanRecord [mAdvertiseFlags=2,
mServiceUuids=[cf2c82b6-6a06-403d-b7e6-13934e602664],
mManufacturerSpecificData={},
mServiceData={000082b6-0000-1000-8000-00805f9b34fb=[49, 50, 51, 52, 53, 54]},
mTxPowerLevel=-2147483648, mDeviceName=null]
Соответствие uuid, к сожалению, результат
byte[] data = scanRecord.getServiceData(uuid)
- null
.
Я заметил, что вывод toString
имел коды ASCII рекламируемых символов данных "123456", то есть 49,50,51,52,53,54
mServiceData={000082b6-0000-1000-8000-00805f9b34fb=[49, 50, 51, 52, 53, 54]}
Я хотел бы получить правильные рекламируемые данные, не делаю ли я что-то не так?
EDIT: манифест имеет разрешения для bluetooth, администратора и местоположения bt. Третий запускает запрос во время выполнения на Android 6
ИЗМЕНИТЬ: напечатав весь файл scanRecord, вы получите этот вывод
ScanRecord [mAdvertiseFlags = -1, mServiceUuids = [cf2c82b6-6a06-403d-b7e6-13934e602664], mManufacturerSpecificData = {}, mServiceData = {000082b6-0000-1000-8000-00805f9b34fb = [49, 50, 51, 52, 53, 54]}, mTxPowerLevel = -2147483648, mDeviceName = null]
В принципе, вы не можете использовать uuid, принятый рекламодателем, который находится в массиве mServiceUuids, потому что ключ, связанный с mServiceData, является другим. Поэтому я изменил код таким образом, чтобы перейти к карте данных и получить значение (см. Два if-блока)
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
for (ScanResult result : results) {
ScanRecord scanRecord = result.getScanRecord();
List<ParcelUuid> uuids = scanRecord.getServiceUuids();
Map<ParcelUuid, byte[]> map = scanRecord.getServiceData();
if (uuids != null) {
for (ParcelUuid uuid : uuids) {
byte[] data = scanRecord.getServiceData(uuid);
Log.i(tag, uuid + " -> " + data + " contain " + map.containsKey(uuid));
}
}
if (map != null) {
Set<Map.Entry<ParcelUuid, byte[]>> set = map.entrySet();
Iterator<Map.Entry<ParcelUuid, byte[]>> iterator = set.iterator();
while (iterator.hasNext()) {
Log.i(tag, new String(iterator.next().getValue()));
}
}
}
}
Действительно, линия
map.containsKey(uuid)
возвращает false, потому что uuid рекламодателя не используется картой данных.
Мне пришлось перемещаться по карте, чтобы найти значение (2-й if-block), но у меня нет никаких средств, чтобы узнать, интересует ли это значение. В любом случае я не могу получить значение if система добавила еще один ключ, который я не могу знать при запуске кода сканера в приложении-получателе.
Как я могу справиться с этой проблемой на ресивере? Я хотел бы использовать поле данных, но строковый ключ для их получения неизвестен априори и определяется системой.