To Subscribe to a topic in an android client we should call:
FirebaseMessaging.getInstance().subscribeToTopic("news");
I want to know what happens if the internet connection is not available at moment that this instruction is executed?
Will google services automatically retry to do subscription when Internet connection become available or we developer should handle this case?
Update:
subscribeToTopic() now returns a Task<Void> so you could attach an OnCompleteListener() to check if it is successful or not.
Update:
So it seems there's more to subscribeToTopic, as per #DiegoGiorgini's comment in your previous post:
subscribeToTopic will keep retry on background, but it's tied to your app lifecycle (not to google services, yet). So if your app is killed it will stop retrying until the app is open again. (the action is stored so it will be resumed when the app is started again)
The way I was trying out before was after the given period, I will be killing the app and didn't pull it up again.
So I've tried checking this out. It seems that if the device is offline when the request for subscription is sent, it will re-try for a period of time (20-30 seconds or so?) then will stop if still not connected. The request probably reached a time-out error. But since there is no return value for subscribeToTopic(), there is no way for you to determine this via your client app. You can send in a Feature Request if you want, pertaining to this.
However, as of the moment, an approach I think that you could do is to have a checker in your client app, where if only the device is online will you send the request.
You can also check it via your app server as I've mentioned in your previous post.
Related
https://developers.google.com/identity/one-tap/android/create-new-accounts
According to the above official documentation, when accessing the googleOneTap function, the third part Display the One Tap sign-up UI will occasionally receive To Error message of failure message 10: Caller not whitelisted to call this API, the google account of the phone itself is unavailable, how to deal with it.
Try to clear the local Google service data, restart the phone, but still can't restore the normal call.
Because this interface needs to be called repeatedly during debugging, I want to inform developers how to avoid or solve the [Caller not whitelisted to call this API] error
Wait about 15 minutes, until you're whitelisted and try again. It's not about code.
I'm building an Android game which requires the user to be online while playing. I'd like to detect if a game was interrupted while playing ( the internet connection was lost \ the device was turned off, etc...),and if it was - this should be considered as a loss for the user, and be written in the database. The only thing I have in mind for now is to save this loss offline, and update it when the user goes back online.
I know I can detect app connection status like this, but it doesn't help be because I can only execute offline operations after this. I also know I can listen to writing events in the database like this, but it doesn't help me, because no child in being updated after the game is interrupted.
My question is: Is there a way to write a Cloud Function which can listen to specific app connection status? If there is no such a way, what are the other options I have?
You can use a onDisconnect() handler. This is a piece of code you run while the app is connected, that sets an operation for the server to run when it detects that the app has disconnected.
A simple example of this from the documentation:
DatabaseRef presenceRef = FirebaseDatabase.getInstance().getReference("disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnect().setValue("I disconnected!");
But I recommend that you read the full documentation on managing presence for more examples.
With this you can have a Cloud Function trigger on the operation of the onDisconnect handler and then update the game status.
Note that it may take a few minutes before the server detects the lost connection in case of a non-clean disconnect.
I have a system where one user can be logged into multiple devices. The use case is as follows:
Suppose the user A subscribes to a weather topic from device A. This user will now get regular push messages from this topic.
Now assume that the same user is logged in to a device B. This device also needs to get subscribed to the weather topic as there is no gurantee that the user will just use device A.
Same use case can be applied in reverse case of unsubscription as well as more than two devices.
What is the best possible way to solve such a problem.
The current approaches which i have thought of are:
1) Make a node under each user id inside firebase db called subscriptions. This node will have subscribed data in the form of
Topidname :boolean issubscribed
This approach has a listener attached to this location in a background service. Each device with the same user id will always listen to the same location thus solving the issue in most cases. It can't gurantee integrity due to the normal service lifecycle reasons.
A service is used because if the listener is kept only for the lifetime of the app, if the user unsubscribes from a topic on one device and the second device app is closed, the second app will keep receiving notifications as it's registration token is still related to that topic and will only unsubscribe on app restart.
Here the service has been made START_STICKY, has a listener inside onCreate and has a backup alarm set to restart the service in onDestroy method. Thus the only case where this won't work is an app force stop or the listener being in a backoff mode due to long non connectivity.
When the app launches it also syncs once with the location and subs the left out topics. Service will stop on signout and unsub from all the previous user's topics. I have kept a keepSynced on the location to ensure it stays in sync
Potential issues are -> service killed by force stop. May cause some ram usage. Sync might not be instantaneous depending on how long the connectivity was lost and how long it takes firebase to resync with the db. Resync and sub unsub all topics in each service restart.
2) This is a relatively more complicated approach:
Save the firebase token from the instance id service for each user in the app server.
On each signout, instead of calling delete iid, keep the same token but overwrite the user attached with the new logged in uid.
On each subscription, do a bulk subscribe to the topic using the Instance Id server api using all the registration tokens for one user.
Each time a user signs out call unsubscribe on all the topics one by one using the instance id api for that device's particular token. Same process for token refresh.
Do to same on unsubscription of each topic.
This case will need one synchronous call for all the topics subscriptions and unsubscriptions. It will also require the token to be constantly updated in the app server.
Please suggest any other better scenario to solve this issue.
If my scenarios have any flaws or needs modifications, please do suggest. I'm stuck and can't think of anything else at the moment.
I'm assuming that you're keeping track of each of the tokens for a user's devices. So the code on your server should be able to know, for a given user, how to send a message to all of their devices, regardless of subscriptions.
Try thinking of user topic subscriptions in the same way that you think of the data broadcasted within those topic. When topic subscriptions change for a user, that event could be broadcast to all of their devices with FCM, telling your app to read the subscriptions from your database and set subscriptions again as necessary. Your app will only wake a receive a notice to change subscriptions when the user requests it.
Then, when it comes time to publish a message to the topic, you can be sure that all the devices that checked in like this will receive the message to the topic.
To boil it down:
1. When a user's subscriptions change in your app, notify the server of that change.
2. In your server, update the user's subscriptions to your database.
3. Then, send an FCM data message to all of the user's devices to reload subscriptions.
4. When that message is received in your app, read the subscription updates out of your database and update the FCM subscriptions accordingly. Your app will have to arrange to stay alive for as long as it takes to do this.
I got an app which uses Firebase.
The Firebase's records holds a "status" field which is supposed to give information if the user is offline or online.
I initialize it like that:
fireBase = new Firebase("https://myProj.firebaseio.com/users");
child = fireBase.child(MyApp.myStringIdentifier);
child.child("status").setValue(ClientStatus.ONLINE);
child.child("status").onDisconnect().setValue(ClientStatus.OFFLINE);
The initialization works fine, and the onDisconnect() is also called after a lot of time there's no internet connection and firebase does change the status to offline as expected.
The problem is that the onDisconnect event is also called when the user swipes out the app from the recent apps list, but I want the user to remain online since I got services which are still running in the background which should handle some events even when the app is closed (They are still running, but other users get the offline status of the closing user and then the actions to that user are blocked) .
Is there a way to prevent to onDisconnect event to be called when the user swipes out the app?
The onDisconnect handlers of your Firebase Database client are called:
when the database client actively disconnects from the Firebase server
when the server detects that the database client has disappeared (by the socket connection timing out)
Note that neither of these has anything to do with your application lifecycle, which seems to be what you are interested in.
If you want to change the database when your application is destroyed, you should probably listen to application lifecycle events to detect when the application exits.
When the user of an Android devices uses the overview display to "swipe away" an app, that's a signal that they don't want to use the app any more, and they're not interested in returning to it any time soon. Android will kill the app process. Killing the app process will close the connection that it has to your Realtime Database. Closing the connection will cause onDisconnect() to execute on the server. You have no control over this process when the user makes their decision. This is by design of the Android platform, which is to allow the user to make the final decision about what can actually run on their device. As the app developer, you are not empowered to force your own decision on the matter.
If you want to send the app a message even though it's been killed by the user, you can instead use Firebase Cloud Messaging to deliver events that the user has expressed interest in.
I have developed android apps, and have a web server application which serves REST style JSON, to the apps.
My apps are strongly dependent on that web services but as traffic gets higher, users' complaint started, as force close problems. I am not sure but maybe my server (AWS small instance) may not answer all requests correctly or in time.
I am planning to retry the web request when a problem on getting json response arise instead giving the error/net-connection alert.
I guess there are many developers who integrates apps with web services, so what is the good practice on handling network problems?
Or is the frequency of such network problems acceptable?
I take about 10-20 problem per day.
I have about 200.000+ web requests per day, for a AWS small instance (1.7 RAM), dedicated to server Tomcat. I analyze the logs there is no clue, no error log. Also the errors are spreaded.
You need to start with analyzing the problem, and determine the root cause or root causes of your issues. You always need to take into account that
a network connection might drop
a users switches from 3G / WiFi
the android devices "thinks" it's connected while in fact it's not
Also, be very sceptical when using the Android ConnectivityManager / NetworkInfo. Only trust it when it states that it is not connected. If it is connected, check it yourself (as sometimes, user is on a hotspot and the only connectivity he has is with a login page).
The application needs to handle all these scenarios properly. The way it's presented to the user depends on the use-case (do you want the user to be informed of the error, do you silently ignore it and just retry, ....)
In terms of retrying webservice connections, there are several ways to implement this :
exponential backoff
periodic rescheduling
event-driven triggering
retry-after moratorium intervals
You need to start by putting sufficient logging both on the client (Android) and on the server (AWS) so that you can analyze the issues and draw the proper conclusions.
I think the answer to your problem lies in the design of your android app.
You need to take into consideration the worst case scenario and redesign your application to take that into account and recover. Dealing with the chaos monkey - jeff atwood.
Personally I never allow an android app to be in a state where it needs to force close. For any or all network connection I assume that the connection is down, lossy, not all data can be retreived and (finally) up and working correctly.
That way my app will degenerate gracefully. If it needs web access it'll make an attempt in a background thread allowing the user to continue using the app, it will cache previous requests and will retry until it gets a connection or gives a nice toast to the end user.