2014-07-09 10 views
10

Recentemente ho iniziato a testare Estimote Beacons e sto provando a lanciare una notifica da un servizio in background quando si entra in una regione beacon, ma sfortunatamente la mia soluzione non funziona. Non dà errori ma la notifica non viene lanciata quando viene scoperto un faro. Non so se si tratta di un errore di codice o semplicemente il modo di farlo è sbagliato. Ho letto this altra questione, ma sembra un po 'diverso dal quello che uso è un servizio invece di un'attività, ma forse la risposta è simile (contesto app correlata) ...Rilevamento regione dei beacon estimetrici da un servizio in background

Ecco il mio codice di servizio

public class BeaconsMonitoringService extends Service{ 

    private BeaconManager beaconManager; 

    private String user; 

    @Override 
     public void onCreate() { 
     // Configure BeaconManager. 
     beaconManager = new BeaconManager(this); 

     } 

     @Override 
     public int onStartCommand(Intent intent, int flags, int startId) { 
      Toast.makeText(this, "Beacons monitoring service starting", Toast.LENGTH_SHORT).show(); 

      user = intent.getStringExtra("user"); 

      // Check if device supports Bluetooth Low Energy. 
      if (!beaconManager.hasBluetooth()||!beaconManager.isBluetoothEnabled()) { 
       Toast.makeText(this, "Device does not have Bluetooth Low Energy or it is not enabled", Toast.LENGTH_LONG).show(); 
       this.stopSelf(); 
      } 

       connectToService(); 


      // If we get killed, after returning from here, restart 
      return START_STICKY; 
     } 

     @Override 
     public IBinder onBind(Intent intent) { 
      // We don't provide binding, so return null 
      return null; 
     } 

     @Override 
     public void onDestroy() { 
     Toast.makeText(this, "Beacons monitoring service done", Toast.LENGTH_SHORT).show(); 
     } 

     private void connectToService() { 


      beaconManager.connect(new BeaconManager.ServiceReadyCallback() { 

      @Override 
      public void onServiceReady() { 
       notifyEnterRegion(0); 
//   try { 
        beaconManager.setBackgroundScanPeriod(TimeUnit.SECONDS.toMillis(1), 0); 
        Log.i("BEACOON ", "ANTES DE"); 
        beaconManager.setMonitoringListener(new MonitoringListener() { 
        @Override 
        public void onEnteredRegion(Region region, List<Beacon> beacons) { 
         Log.i("BEACOON ", String.valueOf(beacons.get(1).getMinor())); 
        for (Beacon beacon: beacons){ 
         Log.i("BEACOON ", String.valueOf(beacon.getMinor())); 
         if (beacon.getMinor() == 64444) { 

          notifyEnterRegion(6444); 

         } else if (beacon.getMinor() == 36328) { 

          notifyEnterRegion(36328); 

         } else if (beacon.getMinor() == 31394) { 

          notifyEnterRegion(31394); 

         } 
        } 
        } 

        @Override 
        public void onExitedRegion(Region region) { 

         notifyExitRegion(); 

        } 
        }); 

      } 
      }); 
     } 

     public void notifyEnterRegion(int code) { 

      Toast.makeText(this, "Beacon "+code, Toast.LENGTH_SHORT).show(); 

      Intent targetIntent = new Intent(this, MainActivity.class); 
      PendingIntent contentIntent = PendingIntent.getActivity(this, 0, targetIntent, PendingIntent.FLAG_UPDATE_CURRENT); 

      Notification noti = new Notification.Builder(this) 
      .setContentTitle("Bienvenido "+user+"!") 
      .setContentText("Sólo por estar aquí has ganado....") 
      .setSmallIcon(com.smt.beaconssmt.R.drawable.beacon_gray) 
      .setContentIntent(contentIntent) 
      .getNotification(); 

      NotificationManager nManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 
      nManager.notify(1, noti); 
     } 

     public void notifyExitRegion(){ 

      AlertDialog.Builder builder = new AlertDialog.Builder(this); 

      builder.setMessage("Hasta pronto!") 
        .setTitle(user+", estás abandonando la zona de beacons"); 

      builder.setPositiveButton("Ver web", new DialogInterface.OnClickListener() { 
         public void onClick(DialogInterface dialog, int id) { 
          // User clicked OK button 
          Intent i = new Intent(BeaconsMonitoringService.this, WebViewActivity.class); 
          i.putExtra("web", "http://www.google.com/"); 
          startActivity(i); 
         } 
        }); 
      builder.setNegativeButton("Adios!", new DialogInterface.OnClickListener() { 
         public void onClick(DialogInterface dialog, int id) { 
          // User cancelled the dialog 
         } 
        }); 

      AlertDialog dialog = builder.create(); 

      dialog.show(); 
     } 



} 

Apprezzerò molto ogni tipo di aiuto, grazie in anticipo!

risposta

8

Questo codice funziona per me. Assicurati di posizionare l'UUID corretto, i numeri minori e maggiori.

//Using something like that as global variable 

    private static final Region[] BEACONS = new Region[] { 
    new Region("beacon1", "uuid1", 1, 19227), //uuid without "-" 
    new Region("beacon2", "uuid2", 1, 61690), 
    new Region("beacon3", "uuid3", null, null) 
}; 
//Note: setting minor == null and major == null will detect every beacon with that uuid 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     startMonitoring(); 
     return START_STICKY; 
    } 



private void startMonitoring() { 
    if (beaconManager == null) { 
     beaconManager = new BeaconManager(this); 

     // Configure verbose debug logging. 
     L.enableDebugLogging(true); 

     /** 
     * Scanning 
     */ 
     beaconManager.setBackgroundScanPeriod(TimeUnit.SECONDS.toMillis(1), 1); 

     beaconManager.setRangingListener(new RangingListener() { 

      @Override 
      public void onBeaconsDiscovered(Region paramRegion, List<Beacon> paramList) { 
       if (paramList != null && !paramList.isEmpty()) { 
        Beacon beacon = paramList.get(0); 
        Proximity proximity = Utils.computeProximity(beacon); 
        if (proximity == Proximity.IMMEDIATE) { 
         Log.d(TAG, "entered in region " + paramRegion.getProximityUUID()); 
         postNotification(paramRegion); 
        } else if (proximity == Proximity.FAR) { 
         Log.d(TAG, "exiting in region " + paramRegion.getProximityUUID()); 
         removeNotification(paramRegion); 
        } 
       } 
      } 

     }); 

     beaconManager.connect(new BeaconManager.ServiceReadyCallback() { 
      @Override 
      public void onServiceReady() { 
       try { 
        Log.d(TAG, "connected"); 
        for (Region region : BEACONS) { 
         beaconManager.startRanging(region); 
        } 
       } catch (RemoteException e) { 
        Log.d("TAG", "Error while starting monitoring"); 
       } 
      } 
     }); 
    } 
} 

*** Montaggio: il codice per calcolare la precisione

public static double computeAccuracy(Beacon beacon) 
{ 
    if (beacon.getRssi() == 0) 
    { 
     return -1.0D; 
    } 

    double ratio = beacon.getRssi()/beacon.getMeasuredPower(); 
    double rssiCorrection = 0.96D + Math.pow(Math.abs(beacon.getRssi()), 3.0D) % 10.0D/150.0D; 

    if (ratio <= 1.0D) 
    { 
     return Math.pow(ratio, 9.98D) * rssiCorrection; 
    } 
    return (0.103D + 0.89978D * Math.pow(ratio, 7.71D)) * rssiCorrection; 
} 

public static Proximity proximityFromAccuracy(double accuracy) 
{ 
    if (accuracy < 0.0D) 
    { 
     return Proximity.UNKNOWN; 
    } 
    if (accuracy < 0.5D) 
    { 
     return Proximity.IMMEDIATE; 
    } 
    if (accuracy <= 3.0D) { 
     return Proximity.NEAR; 
    } 
    return Proximity.FAR; 
} 



public static Proximity computeProximity(Beacon beacon) { 
    return proximityFromAccuracy(computeAccuracy(beacon)); 
} 
+0

Ok, questa soluzione funziona, grazie! ma ho un dubbio a riguardo, come si "computa la prossimità"? è qualcosa nel codice SDK o ufficiale o è la tua soluzione? Quindi da questo capisco che BeaconManager.setMonitoringListener() non è utilizzabile in questo caso e dobbiamo usare setRangingListener() invece ?? – Hugo

+0

Il codice per calcolare l'accuratezza dovrebbe essere nell'SDK. Ma sto usando un'implementazione di sdk personalizzata, quindi ho modificato la risposta per mostrarti il ​​codice. A proposito di setMonitoringListener, non ho potuto farlo funzionare così ho finito di usare questa soluzione. – jDur

+0

Sto integrando per la mia applicazione Xamarin, qui EnterRegion e ExitRegion chiama più volte in sequenza, non so perché? Ho letto su di esso, dovrebbe attivarsi solo quando il dispositivo rientra nell'intervallo di regione. Ma quando entra nel raggio d'azione, si innesca in sequenza fino a quando il dispositivo non si spegne. Gentile aiuto per ordinare questo –

0

controllare questo Spero che questo vi aiuterà. È possibile trovare la vicinanza con questa funzione Utils.computeProximity(nearestBeacon).

beaconManager.setRangingListener(new BeaconManager.RangingListener() { 

     @Override 
     public void onBeaconsDiscovered(Region region, final List<Beacon> beaconList) { 
      if (!beaconList.isEmpty()) { 
       Beacon nearestBeacon = beaconList.get(0); 
       Log.e("Current Proximity - ", String.valueOf(Utils.computeProximity(nearestBeacon))); 
      } 
     } 
}); 
0

dal vostro servizio, si potrebbe anche usare questo library per la ricerca di iBeacons. Potrebbe risparmiare alcuni utenti battery. Preferirei anche questo, dato che BeaconManager in realtà genera il proprio servizio, e quindi hai 2 servizi in esecuzione solo per scansionare iBeacons. Tuttavia manca il calcolo della distanza.

presente inoltre che, per la ricerca di iBeacons necessari:

  • Avere un chip Bluetooth LE: qualsiasi.
  • Avere il Bluetooth attivo: qualsiasi.
  • Avere posizione su: Android 6+.
  • Autorizzazione runtime di posizione: Android 6+.
  • Inizio massimo 5 scansioni in 30 secondi: Android 7+.

E per mantenere il servizio in esecuzione sarà necessario aggiungere le seguenti ascoltatori di trasmissione:

  • Posizione di stato cambiato
  • stato bluetooth cambiato
  • ricevitore avvio

Da queste ricevitori dovresti ricominciare il tuo servizio.