2016-07-07 39 views
12

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.

risposta