To reklamodawca (zawiadomienie data
przekazywane jako AdvertiseData
typu)Android: Skaner Bluetooth Low Energy odbiera dane NULL
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);
}
Zaczyna się pomyślnie.
Jest to skaner
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);
}
};
W zwrotnego onScarnResult
Loguję rekord skanowania toString()
która produkuje tego wyjścia
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 mecze, niestety wynik
byte[] data = scanRecord.getServiceData(uuid)
jest null
. Zauważyłem, że wyjście toString
miał kody ASCII reklamowanych znaków danych „123456”, które są 49,50,51,52,53,54
mServiceData={000082b6-0000-1000-8000-00805f9b34fb=[49, 50, 51, 52, 53, 54]}
Chciałbym otrzymać właściwą reklamowane dane , czy robię coś źle?
EDYCJA: manifest ma uprawnienia do bluetooth, administratora bt i lokalizacji. Trzeci wniosek uruchamia przy starcie w Androida 6
EDIT: drukując cały scanRecord masz to wyjście
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]
Zasadniczo nie można użyć uuid d ecided przez reklamodawcę, który jest w tablicy mServiceUuids, ponieważ klucz powiązany z mServiceData jest inny. Więc zmieniłem kod w ten sposób, aby poruszać się po mapie danych i uzyskać wartość (proszę zobaczyć dwa IF-bloków)
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()));
}
}
}
}
w rzeczywistości linię
map.containsKey(uuid)
zwraca false, ponieważ uuid reklamodawcy nie jest używany przez mapę danych.
Musiałem nawigować po mapie, aby znaleźć wartość (2. blok-if), ale nie mam żadnych informacji, czy jest to wartość, którą mnie interesuje. Tak czy inaczej nie mogę uzyskać wartości jeśli system umieścił inny klucz, którego nie mogę znać podczas uruchamiania kodu skanera w aplikacji odbiornika.
Jak mogę rozwiązać ten problem na odbiorniku? Chciałbym użyć pola danych, ale klucz do ich uzyskania nie jest a priori znany i decyduje o tym system.