Initially I setup a BroadcastReceiver
to receive intents from the Nearby Messages API.
class BeaconMessageReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Nearby.getMessagesClient(context).handleIntent(intent, object : MessageListener() {
override fun onFound(message: Message) {
val id = IBeaconId.from(message)
Timber.i("Found iBeacon=$id")
sendNotification(context, "Found iBeacon=$id")
}
override fun onLost(message: Message) {
val id = IBeaconId.from(message)
Timber.i("Lost iBeacon=$id")
sendNotification(context, "Lost iBeacon=$id")
}
})
}
private fun sendNotification(context: Context, text: String) {
Timber.d("Send notification.")
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notification = NotificationCompat.Builder(context, Notifications.CHANNEL_GENERAL)
.setContentTitle("Beacons")
.setContentText(text)
.setSmallIcon(R.drawable.ic_notification_white)
.build()
manager.notify(NotificationIdGenerator.nextID(), notification)
}
}
Then registered this receiver in my MainActivity
after location permissions have been granted.
class MainActivity : AppCompatActivity() {
// ...
private fun onLocationPermissionsGranted() {
val filter = MessageFilter.Builder()
.includeIBeaconIds(UUID.fromString("B9407F30-F5F8-466E-AFF9-25556B57FEED"), null, null)
.build()
val options = SubscribeOptions.Builder().setStrategy(Strategy.BLE_ONLY).setFilter(filter).build()
Nearby.getMessagesClient(context).subscribe(getPendingIntent(), options)
}
private fun getPendingIntent(): PendingIntent = PendingIntent.getBroadcast(
this, 0, Intent(context, BeaconMessageReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
}
This worked well while the app was open, but does not work when the app is closed. So I found this example, that demonstrates how to setup an IntentService
to receive messages while the app is in the background.
The example does use the Nearby.Messages
class, which was deprecated in favor of the MessagesClient
. So I replaced the deprecated code with the MessagesClient
implementation.
class MainActivity : AppCompatActivity() {
// ...
private fun onLocationPermissionsGranted() {
val filter = MessageFilter.Builder()
.includeIBeaconIds(UUID.fromString("B9407F30-F5F8-466E-AFF9-25556B57FEED"), null, null)
.build()
val options = SubscribeOptions.Builder().setStrategy(Strategy.BLE_ONLY).setFilter(filter).build()
Nearby.getMessagesClient(context).subscribe(getPendingIntent(), options)
.addOnSuccessListener {
Timber.i("Subscribed successfully.")
startService(Intent(this, BeaconMessageIntentService::class.java))
}.addOnFailureListener {
Timber.e(exception, "Subscription failed.")
}
}
private fun getPendingIntent(): PendingIntent = PendingIntent.getBroadcast(
this, 0, Intent(context, BeaconMessageIntentService::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
}
And this is the IntentService
(which is almost identical to my BroadcastReceiver
).
class BeaconMessageIntentService : IntentService("BeaconMessageIntentService") {
override fun onHandleIntent(intent: Intent?) {
intent?.let {
Nearby.getMessagesClient(this)
.handleIntent(it, object : MessageListener() {
override fun onFound(message: Message) {
val id = IBeaconId.from(message)
Timber.i("Found iBeacon=$id")
sendNotification("Found iBeacon=$id")
}
override fun onLost(message: Message) {
val id = IBeaconId.from(message)
Timber.i("Lost iBeacon=$id")
sendNotification("Lost iBeacon=$id")
}
})
}
}
private fun sendNotification(text: String) {
Timber.d("Send notification.")
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notification = NotificationCompat.Builder(this, Notifications.CHANNEL_GENERAL)
.setContentTitle("Beacons")
.setContentText(text)
.setSmallIcon(R.drawable.ic_notification_white)
.build()
manager.notify(NotificationIdGenerator.nextID(), notification)
}
}
onHandleIntent
is called, and the Intent
is not null
; yet for some reason onFound()
and onLost()
are never called. Why would this be the case?
The IntentService is a subclass of the Service class that provides an Android specific implementation of this pattern. It will manage queueing work, starting up a worker thread to service the queue, and pulling requests off the queue to be run on the worker thread.
Step 1: Defining the Processing of Messages. One good reason to use an IntentService is when you have work that needs to occur off the main thread to keep the application responsive and efficient. Another reason is when you may have multiple processing requests, and they need to be queued up and handled on the fly.
The Nearby Messages API combines internet connectivity, Bluetooth, and other technologies to deliver this feature. A Google Account (i.e. Gmail address) for obtaining a Google API Key Two Android devices with Google Play Services (in other words, the Play Store) installed on them
Work is sent to an IntentService by instantiating an Intent and then calling the StartService method with that Intent as a parameter. The Intent will be passed to the service as a parameter in the OnHandleIntent method. This code snippet is an example of sending a work request to an Intent:
It's not really a solution but what I found is this (credit to this answer):
I've tried a few configurations including a BroadcastReceiver
and adding a JobIntentService
to run the code in the background, but every time I got this the onExpired
callback which you can set to the SubscribeOptions
:
options.setCallback(new SubscribeCallback() {
@Override
public void onExpired() {
super.onExpired();
Toast.makeText(context.get(), "No longer Subscribing!", Toast.LENGTH_SHORT).show();
}
}
When the subscribe occurred in the background it was delayed, but it was still called.
Notes:
1. When I've tested with Strategy.BLE_ONLY
I did not get the onFound
callback.
2. From Google's documentation:
Background subscriptions consumes less power than foreground subscriptions, but have higher latency and lower reliability
When testing I found this "lower reliability" to be an understatement: onFound
was rarely called and I never got the onLost
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With