2016-07-07 17 views
12

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.

Odpowiedz