Questo è l'inserzionista (avviso data
passato come AdvertiseData
tipo)Android: scanner Bluetooth Low Energy riceve i dati nulli
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);
}
Si parte con successo.
Questo è lo scanner
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);
}
};
Nella richiamata onScarnResult
accedo il record di scansione toString()
che produce questa uscita
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]
Le partite UUID, purtroppo il risultato di
byte[] data = scanRecord.getServiceData(uuid)
è null
. ho notato che l'uscita toString
aveva i codici ASCII dei caratteri di dati pubblicizzati "123456", che sono 49,50,51,52,53,54
mServiceData={000082b6-0000-1000-8000-00805f9b34fb=[49, 50, 51, 52, 53, 54]}
mi piacerebbe ricevere i dati giusti pubblicizzato , sto facendo qualcosa di sbagliato?
MODIFICA: il manifest ha le autorizzazioni per bluetooth, bt admin e posizione. Il terzo lancia una richiesta in fase di esecuzione in Android 6
EDIT: stampando l'intero scanRecord si ottiene questa uscita
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]
Fondamentalmente non è possibile utilizzare l'uuid d ecidata dall'inserzionista, che si trova nell'array mServiceUuids, poiché la chiave associata a mServiceData è un'altra. Così ho cambiato il codice in questo modo, per navigare nella mappa di dati e ottenere il valore (si prega, vedere i blocchi if-due)
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()));
}
}
}
}
In realtà, la linea
map.containsKey(uuid)
restituisce false perché l'uuid dell'inserzionista non viene utilizzato dalla mappa dei dati.
Ho dovuto navigare la mappa per trovare il valore (2 ° se-blocco), ma non ho alcun mezzo per sapere se questo è il valore che mi interessa. In ogni caso non posso ottenere il valore se il sistema inserisce un'altra chiave che non posso sapere mentre si esegue il codice dello scanner nell'app ricevente.
Come posso gestire questo problema sul ricevitore? Mi piacerebbe utilizzare il campo dati, ma la chiave stringa per ottenerli non è nota a priori e decisa dal sistema.