In my chat app I use FCM with Firebase Functions to send notifications whenever a user receives a new message.
For that I have a FirebaseMessagingService that overrides the onMessageReceived. Aside from that, this Service also overrides onNewToken. Whenever the user first starts the app, the onNewToken gets called and I retrieve a new token and store it in the Firebase Realtime Database.
I then go chat with some user (without closing the app). When I receive new messages, I get the notification. The onMessageReceived gets called.
The problem is, when I close the app and later open it (or turn off emulator and start it up again), and I get a new message from that same previous chat, the service does not get called. I know for a fact that the problem isn't with the Firebase Functions because in my console log I get a Success Message.
Does the Firebase Messaging Service stop when I close and re-open the app?
Here is the code for my Firebase Messaging Service
class MyFirebaseInstanceId : FirebaseMessagingService() {
private lateinit var sp: SharedPreferences
private lateinit var auth: FirebaseAuth
private lateinit var uid: String
private lateinit var token: String
override fun onMessageReceived(p0: RemoteMessage) {
super.onMessageReceived(p0)
if (p0.data.isNotEmpty()) {
val payload: Map<String, String> = p0.data
sendNotification(payload)
}
}
override fun onNewToken(p0: String) {
super.onNewToken(p0)
// Save the new token
sp = getSharedPreferences("AUTH_UID", Context.MODE_PRIVATE)
token = p0
auth = FirebaseAuth.getInstance()
signIn()
}
private fun signIn() {
auth.signInAnonymously().addOnCompleteListener { task ->
if (task.isSuccessful) {
uid = auth.currentUser?.uid.toString()
sp.edit().putString("CURRENT_UID", uid).apply()
sp.edit().putString("CURRENT_TOKEN", token).apply()
FirebaseDatabase.getInstance().reference.child("users").child(uid).child("token")
.setValue(token)
startActivity(
Intent(
this,
MainActivity::class.java
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
}
}
}
private fun sendNotification(payload: Map<String, String>) {
createNotificationChannel()
createNotification(payload)
}
private fun createNotification(payload: Map<String, String>) {
val builder = NotificationCompat.Builder(this)
builder.setSmallIcon(R.drawable.ic_message_not)
builder.setContentTitle(payload["title"])
builder.setContentText(payload["text"])
builder.priority = NotificationCompat.PRIORITY_DEFAULT
builder.setChannelId(Constants.CHANNEL_ID)
val intent = Intent(this, MainActivity::class.java)
val stackBuilder = TaskStackBuilder.create(this)
stackBuilder.addNextIntent(intent)
val resultPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
builder.setContentIntent(resultPendingIntent)
val notificationManager =
(getSystemService(Context.NOTIFICATION_SERVICE)) as NotificationManager
notificationManager.notify(0, builder.build())
}
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Create the NotificationChannel
val name = getString(R.string.channel_name)
val descriptionText = getString(R.string.channel_description)
val importance = NotificationManager.IMPORTANCE_DEFAULT
val mChannel = NotificationChannel(Constants.CHANNEL_ID, name, importance)
mChannel.description = descriptionText
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(mChannel)
}
}
}
Basically, in my Splash Activity I check if it is the first time the user opens the app.
If it is, the login is made from the Service if it is not, the login is made from the Splash Activity.
This is the code for my Splash Activity:
class SplashActivity : AppCompatActivity() {
private lateinit var sp: SharedPreferences
private lateinit var auth: FirebaseAuth
private var flag: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
// If it is first time user enters the app, wait for the MyFirebaseServiceId
// If not, authenticate and sign in (since we already have the token)
sp = getSharedPreferences("FIRST_LOGIN", Context.MODE_PRIVATE)
flag = sp.getBoolean("IS_FIRST_TIME", true)
if (!flag) {
auth = FirebaseAuth.getInstance()
signIn()
}
sp.edit().putBoolean("IS_FIRST_TIME", false).apply()
}
private fun signIn() {
auth.signInAnonymously().addOnCompleteListener { task ->
if (task.isSuccessful) {
sp = getSharedPreferences("AUTH_UID", Context.MODE_PRIVATE)
sp.edit().putString("CURRENT_UID", auth.currentUser?.uid).apply()
getFCMToken()
Handler().postDelayed({
startActivity(Intent(this, MainActivity::class.java))
finish()
}, 2000)
}
}
}
private fun getFCMToken() {
FirebaseInstanceId.getInstance().instanceId.addOnCompleteListener { p0 ->
if (p0.isSuccessful) {
val token = p0.result?.token.toString()
//sp = getSharedPreferences("AUTH_UID", Context.MODE_PRIVATE)
sp.edit().putString("CURRENT_TOKEN", token).apply()
}
}
}
}
What is the problem and why am I not receiving messages all the time?
I faced the same Issue. And It is not the fault of android side.
You can solve this problem by editing notification model/structure by not using any keyword as key,arry name or object name that says notification. Lets say notification {} ===> data{}
NOTE: after doing this you will not receive sounded notice or Automatic notification. You need to manually get the data from the this message and create custom notification using notification manager. Add tittle to it priority and other things...
Doing this you will resolve the problem of notification not being received in background. If you need further assist I can help.
Related
I have a firebase messaging service that gets notifications from a firebase function when a new document is created in firestore.
Below link is the question I've asked about the function.
how to write function for a specific document in firestore?
Now, I'm getting the notification, but I have a problem.check my notification screen shot
First one you see with a date and image. It is when my app is in background.
Second one you see with a notification icon and with some message. It is when my app is open.
below code is for the service.
class MyFirebaseMessagingService : FirebaseMessagingService() {
private val CHANNEL_ID_DEFAULT = "default"
private val manager by lazy {
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
val title = remoteMessage.notification!!.title
val body = remoteMessage.notification!!.body
val intent = Intent(this, MainActivity::class.java)
.putExtra("Type", body)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
var bodymesssage=""
var bodymesssage2=""
if(GetorUpdateUserDataService.PremiumUser)
{
bodymesssage="get 10% of the money"
bodymesssage2="get ₹10 for new install"
} else{
bodymesssage="get 5% of the money"
bodymesssage2="get ₹15 for new install"
}
when(body)
{
"percent"->{
showNotification("Your friend made a withdrawal", bodymesssage, intent)
}
"new_friend"->{
showNotification("Someone entered your refer code","you can get money.", intent)
}
"refer"->{
showNotification("your friend has completed 7 Day Task today", bodymesssage2, intent)
}
else->{
showNotification(title!!, body!!, intent)
}
}
}
private fun createDefaultChannel() {
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID_DEFAULT,
"Default",
NotificationManager.IMPORTANCE_DEFAULT
)
manager.createNotificationChannel(channel)
}
}
private fun showNotification(titlee: String, contexttext: String, intent: Intent) {
// Make PendingIntent for notification
val pendingIntent = PendingIntent.getActivity(
this, 0 /* requestCode */, intent,
PendingIntent.FLAG_UPDATE_CURRENT
)
createDefaultChannel()
val builder = NotificationCompat.Builder(this, CHANNEL_ID_DEFAULT)
.setSmallIcon(R.drawable.ic_baseline_notifications_24)
.setContentTitle(titlee)
.setContentText(contexttext)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
manager.notify(1, builder.build())
}
override fun onNewToken(p0: String) {
super.onNewToken(p0)
Log.d("TAG", "onNewToken: $p0")
}
}
my problem is when my app is in background and when i clicked on notification, it is restarting the app.
when my app is opened (only main activity is opened) and i click on notification, it directly opens the main activity and does what i coded which is what i wanted.
but when my app is opened(and in another activity) it is restarting the app.
i want this to open main activity even it in background or in anther activity.
and also i can get notification when my app is closed in my emulator but not in my Oppo F3 (android 6).
how can i receive notification when my app is not opened?
I am using FirebaseMessagingService to send push notifications to my Pocophone X3 NFC. However, I will send a notification token and erase the notification token from my Firestore database first when logging in and logging out happens. This is to ensure that the notification is sent to the correct user.
To do the above, I have the following code.
#AndroidEntryPoint
class MessagingService :
FirebaseMessagingService(),
FirebaseAuth.AuthStateListener {
#Inject
lateinit var notificationRepository: NotificationRepository
override fun onCreate() {
super.onCreate()
FirebaseAuth.getInstance().addAuthStateListener(this)
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
val title = remoteMessage.notification?.title
val message = remoteMessage.notification?.body
if (message != null && title != null) {
sendPushNotification(title, message)
}
}
override fun onNewToken(token: String) {
saveTokenToSharedPreferences(token)
authRepository.getUser()?.let {
val uid = it.uid
sendTokenToFirestore(uid, token)
}
}
override fun onAuthStateChanged(auth: FirebaseAuth) {
auth.currentUser?.let {
val uid = it.uid
val savedRegistrationToken =
PreferenceManager.getDefaultSharedPreferences(this)
.getString(getString(R.string.fcm_token_shared_pref_key), "")
savedRegistrationToken?.let { token -> sendTokenToFirestore(uid, token) }
}
}
private fun sendPushNotification(title: String, messageBody: String) {
val intent = Intent(this, MainActivity::class.java)
val pendingIntent = PendingIntent.getActivity(this, REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT)
val channelId = getString(R.string.general_notification_channel_id)
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.mlearn_logo)
.setContentTitle(title)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val channel = NotificationChannel(
channelId,
getString(R.string.general_notification_channel_name),
NotificationManager.IMPORTANCE_DEFAULT
)
notificationManager.createNotificationChannel(channel)
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build())
}
private fun saveTokenToSharedPreferences(token: String) {
val sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
with (sharedPref.edit()) {
putString(getString(R.string.fcm_token_shared_pref_key), token)
apply()
}
}
private fun sendTokenToFirestore(uid: String, token: String) {
GlobalScope.launch(Dispatchers.IO) {
notificationRepository.sendNotificationToken(uid, token)
}
}
companion object {
const val REQUEST_CODE = 0
const val NOTIFICATION_ID = 0
}
}
I also registered the service to the manifest like so.
<service
android:name=".service.MessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
The code is working fine when I install the app for the first time and if I don't do any device restarts or app killing. However, when I either
turn off my phone and turn it back on; or
kill the app from my recent apps list
the FirebaseMessagingService code will no longer run. As a result, when I do log in using a new account, the new account does not have the notification token associated with it because the service isn't running.
How do I make FirebaseMessagingService keep running even on app kills and phone turning off and turning on (i.e. restarts)? Note that the app installed is not signed yet.
add this to your service
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
also, it takes some time to receive FCM messages after restart, that doesnt mean your service isnt running. If you start receiving messages after like 5 mins of restart that means your service is working fine, it just takes some time for new tokens to register
if all else fails, check out this project's implementation of FCM, its solid, restarts automatically and saves tokens to firebase
https://github.com/yahyakhan234/PharmaGO2-master
i am using Kotlin Navigation component architecture for my chat app, and i am using Firebase Messaging service to integrate push notification, my requirement is to hide or disable the notifications when i am on User chat screen.Please let me know, how can i achieve this.
this is my code of displaying notification
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
Log.d(TAG, "From: ${remoteMessage?.from}")
remoteMessage?.data?.let {
Log.d(TAG, "data payload: " + remoteMessage.data.toString())
val params =remoteMessage.data.get("body")
val objects = JSONObject(params)
Log.e("JSON OBJECT", objects.toString())
val title = remoteMessage.data.get("title").toString()
sendNotification(messageBody,title, applicationContext)
} }
my notification class is:
fun NotificationManager.sendNotification(messageBody: String, title: String, applicationContext: Context) {
notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// TODO: Step 1.12 create PendingIntent
if(title.equals("Ride Request")) {
fragmentId = R.id.notificationFragment
}
else if(title.equals("Ride Accepted")) {
fragmentId = R.id.inboxFragment
}
else if(title.equals("New Message")) {
fragmentId = R.id.inboxFragment
}
// ---------- creating navgraph intent to open specific fragment ------------
var contentPendingIntent = NavDeepLinkBuilder(applicationContext)
.setComponentName(HomeActivity::class.java)
.setGraph(R.navigation.home_bottom_navigation)
.setDestination(fragmentId)
.setArguments(bundle)
.createPendingIntent()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationChannel = NotificationChannel(channel_id, description,
NotificationManager.IMPORTANCE_HIGH)
notificationChannel.enableLights(true)
notificationChannel.lightColor = R.color.colorPrimary
notificationChannel.enableVibration(true)
notificationManager.createNotificationChannel(notificationChannel)
builder = NotificationCompat.Builder(applicationContext, channel_id)
.setSmallIcon(R.drawable.icon_car)
.setContentTitle(applicationContext.getString(R.string.app_name))
.setContentText(messageBody)
.setContentIntent(contentPendingIntent)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
}else {
builder = NotificationCompat.Builder(applicationContext,
applicationContext.getString(R.string.app_name))
.setSmallIcon(R.drawable.icon_car)
.setContentTitle(applicationContext.getString(R.string.app_name))
.setContentText(messageBody)
.setContentIntent(contentPendingIntent)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
}
notify(NOTIFICATION_ID, builder.build())
}
I don't if this is the perfect but you can try it as well
If the user is in chat screen you can create a sharedPref and set value of the variable to true (that the user is in chat screen)
So in the onMessageReceived() check it the value of the sharedPref is true (which mean the user is in chat screen)
If it's true then don't send notifications if false send notification
To set the sharedPref value
In the onResume of that chat activity set to true
In the onPause set to false
try this
class InboxFragment : Fragment() {
companion object {
var userId: String? = null
}
override fun onStart() {
userId = navArgs.userId
}
override fun onStop() {
userId = null
}
}
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
...
if (InboxFragment.userId != remoteMessage.data.get("userId"))
sendNotification(messageBody, title, applicationContext)
}
}
While using google NearBy Messages API I am getting error " is having trouble with Google Play Services. Please try again"
Please guide me for this issue.
Below is import for Google Messaging API
implementation 'com.google.android.gms:play-services-nearby:17.0.0'
Here is how I am subscribing using code
val options = SubscribeOptions.Builder()
.setStrategy(Strategy.BLE_ONLY)
.build()
Nearby.getMessagesClient(
this, MessagesOptions.Builder()
.setPermissions(NearbyPermissions.BLE)
.build())
Nearby.getMessagesClient(this).subscribe(getPendingIntent(), options)
I resolved it.
Nearby suggest using activity, on activty, the function will work better (https://developers.google.com/android/reference/com/google/android/gms/nearby/messages/MessagesClient#subscribe(android.app.PendingIntent,%20com.google.android.gms.nearby.messages.SubscribeOptions))
All of the Messages APIs should be used from a foreground Activity,
with the exception of the variants of subscribe that take a
PendingIntent parameter. Your Activity should publish(Message) or
subscribe(MessageListener) either in onStart() or in response to a
user action in a visible Activity, and you should always symmetrically
unpublish(Message) or unsubscribe(MessageListener) in onStop().
When subcribe, if using activity, it will ask to grant permission to bluetooth, location, microphone, if using service it will not ask
So if you use the service, you must combine using the activity.
When you subscribe in mainActivity, if another activity appears on top (then MainActivty will be onStop), a notification will appear.
Therefore, when subcribe, you must click OK to allow the another activity to be displayed
This is sample:
MainActivity.tk
private val mMessageListener: MessageListener = object : MessageListener() {
override fun onFound(message: Message) {
Log.d(TAG, "onFound message:"+ String(message.content))
}
override fun onLost(message: Message) {
Log.d(TAG, "Lost sight of message: " + String(message.content))
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val sharedPref: SharedPreferences = getSharedPreferences("MyPref", Context.MODE_PRIVATE)
val isFirstTime = sharedPref.getBoolean("FIRST_TIME", true)
if(isFirstTime) {
Nearby.getMessagesClient(this).subscribe(mMessageListener).addOnCompleteListener(this, OnCompleteListener {
requestPermissionFirstTime()
}).addOnCanceledListener(this, OnCanceledListener {
requestPermissionFirstTime()
})
} else {
requestPermissionCapture()
checkPermissionAccessibility()
startService(Intent(this, NearbyMessageService::class.java))
}
}
private fun requestPermissionFirstTime() {
val sharedPref: SharedPreferences = getSharedPreferences(Utils.IAMHERE_PREF, Context.MODE_PRIVATE)
val editor = sharedPref.edit()
editor.putBoolean("FIRST_TIME", false)
editor.apply()
Nearby.getMessagesClient(this).unsubscribe(mMessageListener)
requestPermissionCapture()
checkPermissionAccessibility()
}
NearbyMessageService.tk
class NearbyMessageService: IntentService("NearbyMessageService") {
private val mMessageListener: MessageListener = object : MessageListener() {
override fun onFound(message: Message) {
Log.d(TAG, "onFound message:"+ String(message.content))
}
override fun onLost(message: Message) {
Log.d(TAG, "Lost sight of message: " + String(message.content))
}
}
override fun onCreate() {
super.onCreate()
startForeground()
Nearby.getMessagesClient(this).subscribe(mMessageListener)
}
private fun startForeground() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = "002"
val channelName = "Nearby Service Channel"
val channel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_NONE)
channel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(channel)
val notification: Notification = Notification.Builder(applicationContext, channelId)
.setOngoing(true)
.setCategory(Notification.CATEGORY_SERVICE)
.setContentTitle(getString(R.string.app_name))
.build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(Utils.NOTICATION_ID_NEARBY, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION)
} else {
startForeground(Utils.NOTICATION_ID_NEARBY, notification)
}
} else {
startForeground(Utils.NOTICATION_ID_NEARBY, Notification())
}
}
}
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?
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.
I know this is a late reply, but I had the same problem and found out by debugging that it is an issue related to this error: "Attempting to perform a high-power operation from a non-Activity Context". This can be solved when calling Nearby.getMessagesClient(this) by passing in an activity context instead of this.
In my case I added a class extending Application which helps in returning this context (the below is in java but should be translatable to kotlin easily)
public class MyApplication extends Application {
private Activity currentActivity = null;
public Activity getCurrentActivity(){
return currentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.currentActivity = mCurrentActivity;
}
}
And in my base activity, from which all activities extend, I set the current activity by calling ((MyApplication) this.getApplicationContext()).setCurrentActivity(this); in the constructor.
My service can then call getMessagesClient with the correct context like below:
final Activity context = ((MyApplication)getApplicationContext()).getCurrentActivity();
Nearby.getMessagesClient(context).[...]
Do not forget to register your Application class in the AndroidManifest:
<application
android:name="com.example.xxx.MyApplication"`