I'm trying to place a best guess estimate as to whether C2DM messages can be received.
I've created an application that relies on pushing information to a phone while it is physically inaccessible. I understand that C2DM isn't guaranteed delivery, but I'd at least like to know when the delivery of a message is even possible; when it isn't we fall back to our own push service (and can actually tell when we're connected).
I've noticed C2DM on android will still issue auth tokens even when there is not a logged in google account; messages still seem to be delivered in this instance even though it's stated that they shouldn't be. If GTalk isn't connected (firewall or other reasons), no response at all is returned when requesting an auth token. Auth tokens are returned to the application when the phone is in airplane mode. This means it's not as simple as checking if an internet is available. I can't find a reliable way of checking if GTalk is logged in.
Again, I don't need to guarantee the delivery of messages, but I'd at least like to know if delivery is even possible. Does anyone have interesting solutions?
Go watch this video, it's a Google I/O talk about C2DM, how to use it and how it works. AFAIK, you can't know if it's connected or not. Probably most of the time they don't even know (until they have to deliver a message and fail).
However, it is highly recommended (in the video as well) that you do not send important data through C2DM (as messages can get lost). The service should only be used as a "network tickle" (with a footprint as small as possible). Your application should be woken up by this tickle and it should start fetching the information it needs itself.
Now, if you implement it this way, it should be easy to implement a polling mechanism. Since you already separated the "tickle" from the actual information retrieval, you can just trigger the retrieval every once in a while if there's no tickle.
Something you can do to check whether C2DM is connected is something like a ping:
Send message to phone via C2DM
The app receives (or doesn't receive) the message and sends a "pong" back to your server
The server waits for the "pong" for a predetermined amount of time (1-2 minutes, I'd say) before marking the device as "offline".
Edit: relying on GTalk is not feasible. GTalk relies on C2DM just like your app, it doesn't have anything "extra". Also, GTalk is not present on all devices. I'm not sure how the GTalk app determines whether it's offline or not (it's not open source, unfortunately), but I'd guess it just tries to ping a server and fails.
No that is impossible.As you device authenticated once and generate registration ID and send to third party server(As you already know).Now your work is over once the device has been registered.So Wait for message either you got or not(No guarantee of delivering message as C2DM used UDP Protocol ).
Alternative Solution
Although its impossible to check from Google side directly as i mentions above,But if you have any urgency to check connection from your phone
then you can take approach like this
Step 1): Make one Web service to check connection
Step 2): Call this web service from application that will command to server to send push notification for checking purpose.
Step 3): Now from server side,server will immediately send push notification for particular device(FROM which it get command)
Step 4): Now if you got push notification that means you are still connected to C2DM.
this will not take much time.But follow it only when checking connection is urgent and it is on user
This may be a bit naive as I am not an active C2DM user, but wouldn't it be possible to read
/proc/net/netstat
and see if there are any active TCP connections. If there aren't any, then C2DM can't possibly be working. You could also make this technique more versatile by forming a C2DM whitelist that you would expect to find (or maybe its possible to filter on a special C2DM port?)
If the device is inaccessible, even your fallback push messaging system wouldn't work. The C2DM doesn't guarantee that it will deliver your message, but the event of non-delivery would be very rare. So would be the case with any other service. The best workaround that you could have is to poll your server to check if you have any new messages that hasn't been delivered yet. I am assuming that your application is such that it's very important not to miss even a single message in 500 or may be 1000. In that case, you could implement a hybrid of push and pull.
I've worked a little with C2Dm, I've created my own push 3rd party server .
I've implemented a little logic based oh C2DM http response code to know if a push message was sent or not .
Here is some of the code I used :
int responseCode = conn.getResponseCode();
if (responseCode == HttpServletResponse.SC_UNAUTHORIZED || responseCode == HttpServletResponse.SC_FORBIDDEN) {
LOGGER.warn("Unauthorized - need token");
return false;
}
here I'm almost sure that the push message was sent from the c2dm servers because I've got an id ont the response:
if (responseParts[0].equals("id")) {
LOGGER.info("Successfully sent data message to device: " + responseLine);
return true;
}
I've used other methods to get other result codes from Google if you want I can post them.I hope that I've helped you a bit .
I don't think there's any way to determine in ADVANCE whether there's any chance a push attempt will work, but I can think of a fairly straightforward way to verify receipt (but not queueing for future delivery via C2DM) -- just complete the message loop.
Remember, C2DM's main benefit is that it allows notifications when then phone is asleep and nominally offline. Once your application gets the notification, there's little to stop you from waking up the phone at that point, bringing up the network, and sending a confirmation. I don't think you'd even have to request "keep phone awake" permissions, because I believe the mere act of having registered for C2DM notifications and receiving one is sufficient to wake up the phone and allow the app to continue running normally (at least, long enough to bring up the network and send the confirmation).
While you're at it, you should keep track of confirmations that happen LONG after you expected them to be a lost cause. If you see more than a few, you might have to alter the resend strategy.
The only real-world edge case where this might fail is if you had users who bent over backwards to disable data while leaving voice/SMS enabled (I'm pretty sure C2DM uses 4 bytes of the response datagram sent when a phone polls for incoming calls & text messages that were originally set aside for RIM, then later repurposed for Apple and Google).
try to shut down all network connections and reconnect again. if you will get an registration id, then you can receive messages.
Something related to the long running C2DM-connection that is used to deliver the triggers:
On WLAN it sends a heartbeat every 15 minutes.
On mobile networks the timeout is 28 mintes.
28 Minutes might be to long, depening on the hardware your mobile carrier uses, 2g/3g repeaters in garages, etc.
You can get lots of information about the connection by opening the Google Talk Service Monitor Application: http://www.honeytechblog.com/monitor-google-talk-service-android/
Dial: ##8255##
Theres also a button that sends a heartbeat right now and resets the timeout.
If you want to ensure (on the client side) that c2dm-messages can be received at a given time, your best bet is to re-send the heartbeat. This can be done programmatically - only on rooted devices though. I might release an apk to the market sometime that does exactly that.
Related
It seams like to work with chat application, using openfire and smack there can be two ways below,
First Way
Smack makes a connection with the openfire server and it can receive and send updates to the server as long as its connected to the openfire server. In case its not connected, theres a plugin on openfire which keeps the messages offline, and send them once the client is connected again.
In this scenario to receive all messages,
1.1 Device should only disconnected from the openfire in case if it don’t have internet.
1.2 User is sign out
1.3 Device is offline
If connection goes disconnected with the server in any other case this cause messages loss. Currently application is working with this architecture.
Problems with this method:
The major problem for this is if due to any crash, or problem application gets completely killed, and its not alarm manager task also gets killed. App didn’t restart until the application opens again.
Second problem with this is, its consuming battery due to continuous process
On updated OS application goes in deep sleep, doze mode, ulta power save mode, background
Second Way
2.Smack makes a connection with the openfire server and it can receive and send updates to the server as long as its connected to the openfire server until the application is in foreground. As soon as this goes in background the application will completely disconnect from the server. In this case as application is offline openfire have to send all the messages to the Firebase server, same application listens for the firebase notifications and when it receives the notification from firebase it reconnects to the openfire and gets the message and display or shows the message directly from firebase (in this case this record goes to the firebase server as well). Application receives that notification from the gcm and then need to manage in application about message delivery etc.
Problems
Disconnect from server when app goes in backgound, handle its usecases as app is in background for long time or not. Is app goes in background to select any file and use cases like this.
This makes the code and application very compelex and need to manage multiple servers as well.
There can also be more security breaches as i don't want to share my application messages data with any third party.
My Questions
Which way is better, secure and more reliable to use?
My application is working with way 1, should i switch to second way ?
what can be possible reasons to make sure that app stays connected in each and every way? and it consumes less batter as well?
1- Which way is better, secure and more reliable to use?
A: Second Way
2- My application is working with way 1, should i switch to second way ?
A: You should but obviously that would require Openfire skills to develop a plugin which will route messages to FCM.
3- what can be possible reasons to make sure that app stays connected in each and every way? and it consumes less batter as well?
A: Simply said, if we reduce XMPP traffic, processing power can be saved and as a result reduction in battery consumption. But obviously for a chat application, that won't be the option. So for keeping the application interactive and battery friendly you should disconnect XMPP when app goes to background and rely on Push notifications (integration on server side).
I am trying to use GCM service, Every thing is OK except of the long delay that GCM push notification or deliver payload... some times it take to my App 5 minutes receive notification or payload.
I need Immediate delivering...
I know about the roles of GCM, that wait until the other device got online, but in my case I hold two devices and they are online, but I got Delayed notifications!
How does WhatsApp(as example of app that uses GCM) overcome this problem.. and send Immediately?
[ i.e (message of the type: typing, online - last seen) cannot be delayed...]
the GCM Delayed Push is known problem : this issue
my question is: How other app that use GCM overcome this issue
The big players
Lets focus on WhatsApp from a scale point of view. Their scale is global and one of the largest in terms of the market share. For players like these it becomes necessary to provide a consistent and smooth user experience no matter what the circumstances are. This means that the "small fish developers" like us are left with pre-defined rules by the big fish companies. Sometimes, it is the implementation that is challenging enough that a lot of the small time developers have to do with whatever is available.
I would like to take WhatsApp's Push Notification as an example to illustrate the above.
First of all, we must stop associating Push notification with Google's services(i.e, Google Play Services) exclusively. Would a device without Google Play services won't receive Push notifications? No, of course it can -- try focusing on the core mechanism of a push notification
How do Push Notifications work - Sockets!
Contrary to a protocol like HTTP which assumes a client-server architecture and is a uni-directional protocol(server can't initiate communication by itself), a plain socket enables communication bi-directionally.
You want to implement your own File transfer protocol over socket? You can!
You want to implement your own Chatting protocol over socket? You can!
You want to implement your own Push notifications protocol over socket? You can!
A socket is the canvas of communication over a network. You can pretty much do anything. Personally we have developed a custom request-response protocol in our organization.
Multiple implementations
Don't stick with default GCM/FCM notification messages protocol or implementation. You can deploy a mechanism to maintain a persistent socket connection with the device and can listen to whatever the server wants to push.
WhatsApp uses both GCM/FCM as well as their proprietary XMPP server implementation for Push notifications
WhatsApp(and several other Apps) rely upon GCM/FCM(as option 1 - the default) as it is present as a system App on lot of devices and therefore holds a special status where it is very less likely to be killed unlike a normal App.
For devices that do not have play services, your custom socket connection is relied upon. It may be that FCM is preferred over socket when the former is available but those are upto you to manage.
From WhatsApp's latest build(2.19.203):
Notice that the relevant permission for FCM is present.
Suspected socket implementation: https://android.stackexchange.com/questions/43970/how-is-whatsapp-able-to-receive-messages-when-not-in-use
XMPP based Push Notifications
From, https://www.quora.com/Does-WhatsApp-use-GCM-to-exchange-messages
No, whatsapp doesn't use GCM[NOT entirely true]. It uses a modified version of XMPP
called FunXMPP instead. It changes the XML keywords in message frames
to save bandwidth as it's users aka mostly mobile network users,
doesn't have a good internet connection. The replacements can be found
here: mgp25/Chat-API (I am not the author though)
They have even asked for whitelisting of any port(custom) in use by them.
So, WhatsApp does it. Facebook does it. Google does it. A lot of these companies do this. You can do it as well(to an extent) using Ejjaberd, Openfire or some other technology and having a proper client side implementation for the same.
Chinese ROMs
Some chinese ROMs have taken it even further and radically changed the way the memory and processes are managed in Android. As an example, in Oppo if the Application doesn't have Auto Start turned on, it will not let you do anything once your App is killed. No hopes of any experience whatsoever except hoping that the user will open the App again. In these cases, these OEMs have whitelisted WhatsApp, Facebook, Google and other players selectively. So, who suffers?
Us. Period.
When sending your notification you could set the priority-parameter to "high".
From the docs:
By default, messages are sent with normal priority. Normal priority optimizes the client app's battery consumption, and should be used unless immediate delivery is required. For messages with normal priority, the app may receive the message with unspecified delay.
When a message is sent with high priority, it is sent immediately, and the app can wake a sleeping device and open a network connection to your server.
I know this answer comes late, nevertheless if you are still facing this issue (or anyone else) please tell me if it helps.
I'm trying to develop a turn base game over XMPP. ( The only solution I found for multiplatform game ). I can send messages without problems. If the other user isn't online, the server (OpenFire) save it for later deliver.
The problem cames when a device change the network ( change from 3g to WiFi, change 3g IP... ) or the device lost the network ( turn off 3g, wifi or lost connection ). The server thinks that the device is online and send the message but it ( obviusly ) never arrive, so packet is lost.
I know one solution. Implement ACK over my game protocol, but I don't like this idea to much. Do you have any other suggestion? I think this is a server problem. Do you know another server witch implements TCP or ACK?
Thank you!!
EDIT: I do that: Connect device to server. I turn down the 3G and WiFi connectivity to the device. Android and the server still thinking that the connection is alive.
http://issues.igniterealtime.org/browse/SMACK-331
PD: I ask to openfeint for they multiplayer api, but they didn't asnwer me...
Although BOSH will likely work in this case, another option is XEP-0198: Stream Management. This will allow you to have all of the performance of a fully-connected socket, along with quick reconnects, positive acking, and queuing while un-acked or disconnected in both directions.
Under some conditions TCP/IP is not reliable. This is why ACKs, message receipts, IQs or other extensions in XMPP can solve this problem.
I have done lots of mobile programming over the years, also often with Openfire. But I have not seen lost messages. So I assume that there is a problem in either the library you are using on Android, or the Openfire version you use.
Instead of using raw sockets you can also use BOSH:
http://xmpp.org/extensions/xep-0124.html
BOSH is based on WebRequests like Comet and works very well in environments where you switch or loose often the connection. It can keep the connection alive until your network is back and does not result in connection drops when one or more requests fail in a row.
I too came across this issue and been trying to figure out a proper way to get this resolved.
Problem for me is that I set the offline messages policy to "Always Store" and thus XEP-0184 doesn't really help out to determine if a message is not getting delivered to its receiver.
Providing this scenario:
- I have 2 users chatting, call them A and B
- A sends B a message while B's connection just got lost
- The message got dropped and A is not notified
- In this case A does not know that the message got dropped, it'll just assume that the message is delivered to the server, server will eventually deliver it to B
- B lose the message forever
So I temporarily put in a work around for this... i store all those messages that are not delivered (i.e. haven't receive the message delivery receipt) into a queue, then periodically (say, 6 minutes - it's the time when those dead connections got wiped) check every message of the queue to see if the intended recipient is "Online" AND the receipt's still not received... If it's the case, then I mark that message as "Failed delivery"
This is quite a terrible way to fix it (please advise if you have a better way of doing it). I think the best thing to do is to have the server to do this: if message failed to deliver and the offline message policy is "Always Store", then we store it to "ofoffline" for delayed delivery.
This is an old one, but I was solving such an issue recently. It helped me when I set the XMPP resource (the last part of full JID) to something reasonable, when building connection. Otherwise it will be random generated on each reconnect - and that changes the full JID.
I am having issues with C2DM. Sometimes works perfectly, sometimes my messages simply do not get pushed. Is there reliable way to enforce this connection? To pull messages. I read somewhere that what google do is keep low bandwidth TCP connection to their server at all time. So I assume that
when switching between network types TCP connection falls down and Android tries to reestablish connection to C2DM servers. So that might fail on WiFi with restricted network. Is that wrong assumption?
I have noticed with WhatsApp that on WiFi sometimes I do not get messages. When I switch to 3G I usually get them at the moment of the switch. What tips from your experience with C2DM would you offer?
C2DM is not suitable for critical parts of your application, since Google currently does not offer an SLA or paid tiers that will guarantee you reliable service and throughput.
I've considered several alternatives myself: XMPP via asmack, Parse, Deacon, Urban Airship, and MQTT.
After some reading and experimenting I decided to go with MQTT. It is a very lightweight telemetry protocol invented at IBM that fits quite nicely in the Android push notifications scenario. I recommend you give it a try, here's a nice blog post to guide you: Using MQTT in Android mobile applications.
Hope this helps.
C2DM does not guarantee that your message will be delivered, and your application should not assume that in order to work correctly. Therefore, your C2DM message should never contain the data itself but, rather, a notification that there is data available. In other words, the loss of a C2DM message should never cause your application to lose data; it should, at most, cause it to take longer to notice that a certain piece of data is available on your server.
A typical app should connect to its server once in a while (a long while) to retrieve messages, even when using C2DM, to cover the case where C2DM messages might not be delivered.
Depending on network configuration, the device might not be able to receive C2DM messages; restrictive firewalls or other strange WiFi configs might do that.
With C2DM reliability is not a guarantee. So best to have a ACK
message or some way in which you (the sender) the realize the message was received successfully.
Also make it a point to override onRegister class properly because the device Reg ID keep on shuffling.
Lastly, if you are planning to send updates regularly, I'd prefer polling to C2DM just because of the amount of requirements to get it functioning while reliability and ultimate control is still not assured.
I've been struggling with the same problem myself. The behaviour you describe is accurate. I'm developing an app that uses c2dm mainly with Wifi connection, and I had to implement an AsyncTask to periodically (minute and a half) call WifiManager.reassociate() (turning wifi off and on again triggers the arrival of all pending notifications, that's what inspired this solution) so I can keep the notification arrival as accurate as possible. Not so sure about the correctness of this practice, though.
Have you tested it every 15 minute connection? I created a schedule task to send the message. I use NotifyMyAndroid to push it. C2DM sometime pushes the message about 10 mninutes after not instantly. But, sometimes you get it in around a second.
The best way you can do this is by testing. I have a mechanism in my app that when I enable debugging I receive a HTTP request from the client saying that they received the message.
I find that this number is about 80%. Fortunately that's enough for the scope of my application.
Wifi shouldn't interfere in the C2DM ability of receive messages. At least while the phone is active.
What happens is that android turns the wifi OFF after the phone is in standby for a while. The messages won't be available at that period of time, simply because there's no internet connection available. Right after the user wakes the phone up, they should receive the messages.
After a long time research pretty much "all the internet" for an answer, I've found it. As I posted before, I was struggling with the problem myself and found out it was not a C2DM problem, or even a implementation problem. It was simply a router or firewall misconfiguration. Android uses a persistent TCP connection with a heartbeat keep-alive mecanism to ensures that the connection stays up. Google uses the state of the connection to determine if your device is idle or not. But if your router has a protection policy that checks for "unused" connections and terminates them, that won't work. Android notifications should be delivered (close to) instantly. I've tested this in my school network and home network, with two diferrent behaviour.
To resume: be sure to check your network configurations.
Some APNs work better than others with C2DM. Google "gtalk apn", for example, to find forums about the impact of the APN on C2DM.
I'm currently in the process of developing an app which has some very demanding needs.
The Project
An application which can communicate with a server is needed.
Small messages has to be send to the app which could display a notification or start an activity.
The Demands
Client needs to be sure that the phone is 'connected' at all times.
The client expects that the app can tell when it's no longer connected (or able to connect) to the server it tells the user.
Client needs to be able to send a message to individual devices
If the client needs to broadcast a message to the connected devices and to the individual devices.
My thougts (or problems)
Currently, the app is polling the server with a http request once a minute - if the app isn't able to connect to the server the user gets notified. The polling is able to tell which device is calling and telling it if it has a message for it.
But...
IMO this is a terrible design - it generates a lot of excess traffic, uses resources which probably wasn't necessary and it offers a lot of issues with connectivity (which I'm not sure I'll ever get past no matter which method is used).
I need your experience to select the right solution for my project.
I've been thinking of C2DM, but I'm not sure this could cover my needs?
Is polling for my only real solution?
Is there a third option I haven't thought about?
I stumbled upon a new service called Parse.com they seem to offer functionality for easy push-implementation for Android using their backend. It's commercial but they have a free plan too.
If you want to do your own implementation there seems to be a lot of articles about using MQTT which is designed for low-power devices. But I haven't seen any ready-to-use implementations of this yet.
I'd consider MQTT as a good solution, although it is what I'm most familiar with. Disclaimer - I write an Open Source MQTT broker. You could achieve what I think you want like this:
Have an MQTT broker running somewhere. The service on the phone connects to the broker and subscribe to a unique topic, e.g. device/23412364, where 23412364 is the per device unique id and referred to as <phone id> below. When your client wants to send a message to a specific phone, the message goes to device/<phone id>. If you want messages to go to all phones, then the phones could also subscribe to device/all for example.
If you make your subscriptions and messages have Quality of Service of 1 or 2 and set the "clean session" option for the clients to false, then messages will be queued up on the broker if the phone disconnects for whatever reason. QoS=1 means "at least once" and QoS=2 means "exactly once". When the phone reconnects, those messages will be delivered.
You could also have the phone send a message like "register <phone id>" to a fixed topic just after it connected (topic of "register" for example). A feature of MQTT that is very useful is the "Last Will and Testament". When you connect a client, you have the option of specifying a Will message and the topic that it should be delivered on, in the case that the client disconnects unexpectedly (ie. without telling the broker that it is going to disconnect). So you could set the will message to be "unregister <phone id>" and to be delivered to the same fixed topic as above ("register" in this example). You could then have another MQTT client at the server end sitting subscribed to "register". When a phone connects, it sends a "register <phone id>" message, when it gets disconnected the broker sends "unregister <phone id>". The MQTT client can therefore keep track of the connected clients at the server side.
At the phone end of things, you can get notified if the TCP connection goes down through normal network code.
Some relevant links:
Using MQTT in Android mobile applications: http://dalelane.co.uk/blog/?p=1599
Trivial MQTT Android project based on above: http://mosquitto.org/2011/11/android-mqtt-example-project/
MQTT Power Profiling: http://stephendnicholas.com/archives/219
MQTT features: http://mosquitto.org/man/mqtt-7.html
Facebook using MQTT: http://www.facebook.com/notes/facebook-engineering/building-facebook-messenger/10150259350998920