2016-07-07 2 views
12

Ceci est l'annonceur (avis data passé comme AdvertiseData de type)Android: scanner Bluetooth Low Energy reçoit des données nulles

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); 
} 

Il commence avec succès.

C'est le 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); 
    } 
}; 

Dans le rappel onScarnResult je me connecte le dossier d'analyse toString() qui produit cette sortie

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] 

Les matches UUID, malheureusement le résultat de

byte[] data = scanRecord.getServiceData(uuid) 

est null. Je remarqué que la sortie toString avait les codes ASCII des caractères de données annoncés « 123456 », qui sont 49,50,51,52,53,54

mServiceData={000082b6-0000-1000-8000-00805f9b34fb=[49, 50, 51, 52, 53, 54]} 

Je souhaite recevoir des données le droit annoncé , Est-ce que je fais quelque chose de mal?

EDIT: le manifeste a des autorisations pour bluetooth, bt admin et location. Le troisième lance une requête lors de l'exécution dans Android 6

EDIT: en imprimant l'ensemble scanRecord vous obtenez cette sortie

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]

Fondamentalement, vous ne pouvez pas utiliser l'uid d géré par l'annonceur, qui se trouve dans le tableau mServiceUuids, car la clé associée à mServiceData en est une autre. Donc, j'ai changé le code de cette façon, pour naviguer sur la carte de données et obtenir la valeur (s'il vous plaît, voir les deux si-blocs)

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())); 
       } 
      } 
     } 
    } 

En fait, la ligne

map.containsKey(uuid) 

renvoie false parce que l'uuid de l'annonceur n'est pas utilisé par la carte de données.

Je devais naviguer sur la carte pour trouver la valeur (2ème if-block), mais je n'ai aucun moyen de savoir si c'est la valeur qui m'intéresse. De toute façon je ne peux pas obtenir la valeur si le système met une autre clé que je ne peux pas savoir en cours d'exécution du code du scanner sur l'application du récepteur.

Comment puis-je gérer ce problème sur le récepteur? Je voudrais utiliser le champ de données, mais la clé de chaîne pour les obtenir n'est pas connue a priori et décidée par le système.

Répondre