I am developing a backend service that sends push notifications to mobile apps via either FCM or APNS. I would like to create an automated test that can run in under a minute and validates that the server can successfully send a notification. Note that I do not necessarily need to check that the notification has been delivered, just that FCM or APNS has successfully processed the request to send the message.
I know that theoretically I could automate this test using a tool like appium and use test hooks to retrieve a registration/device token from the app, but it seems cumbersome to use appium to test if the backend can send a message. I have also tried to use a hard coded registration token, but registration and device tokens are prone to rotate, so the test could suddenly stop passing. Are there any other options?
First of all, I would think about what scenario do we want to cover.
Maybe, we want to check that we sent a request to FCM when it is needed. This case might be done on a unit level with mocked classes responsible for sending a push.
If you want to test specifically success of the FCM call, then you don't actually need a correct Firebase token of the user device. According to docs, if everything is configured correctly and you send a message to a user using incorrect token (or even without it), you will still get http code 200. As a result, you may use usual integration test that will call Firebase API and check the success code (200) and error field (MissingRegistration / InvalidRegistration / NotRegistered), and if you get such a pair - your request was succesfull. There is no much need to test it with a correct user device token, because if everything else is correct, the result will be the same (but actually delivered to a phone).
Firebase docs
In case if you still want to use an actual token, you can create a special build type for you QAs, that will send their Firebase token to a special endpoint on your server on each app start. As a result, you will always have a recent Firebase token stored on your server to use for test purposes. Of course, that test may still be flacky but it is a good starting point.
Appium is automation framework for black-box testing, so in your case, it allows to check if the notification pops up on a device. And that's it.
Appium has no access to your application code, you can send adb commands via it, but basically, no way to play with tokens until you expose it to the UI layer of your app.
Moreover, Appium is not supported by Firebase.
I suggest looking into Espresso, where you write tests with direct access to your application code.
You can write cloud functions to achieve this in firebase which can be pushed using firebase CLI from local system.This cloud functions can be written in Nodejs. You can go this documentation for writing cloud functions. https://firebase.google.com/docs/functions/ These cloud functions can be triggered on some events like change in real time database,when user signup etc. and you can get tokens from mobile app using callbacks on registered listeners and we can use them to push notifications to app. You can go through following simple project. https://aaronczichon.de/2017/03/13/firebase-cloud-functions/
Related
I trying to understand how FCM (Push notifications) works... and that is very differ with Web applications...
What I did →
Register new project in Firebase
Added App com.google.firebase.quickstart.fcm and download google-services.json
Built App using google-services.json in Android Studio
Install APK on my device
Go to https://console.firebase.google.com/project/{PROJECT_NAME}/notification and sent new notification
And... nothing happens
So my questions are
As I know here is two ways to send notification: a) use device token and send direct notification, b) subscribe device to topic at client side.
But
a) When I try to create New notification in firebase console, here is no field where I will be able to insert device token. Here is Target → Target user if → App → com.google.firebase.quickstart.fcm. So do I need to know device token or I can send notifications to all clients that have my app installed on their devices?
b) When I trying to send message on weather topic nothing happens. Even if I pressed button Subscribe to weather (In manual you may find Subscribe to News, but actual version button is weather)
Is there any way to check (especially at server side) if my device registered in FCM or not?
What is the most effective way send same contents on big number of devices (for example 50000) with minimum time lag? Try to loop over device tokens (1000 tokens per request) or using topics? Is there any other ways?
Actually my backend is AWS SNS in pair with FCM, so if you can answer about most effective way in case of SNS + FCM that will be brilliant
I don't know... any suggestions? I'm a web developer (REST, etc...) and have zero experience with mobile apps
1- You will need to store the current device tokens in a database to then loop through each one to send a message.
Topics need to be subscribed to from the client side and have limited use
2 - you should be storing it in a database, sending an FCM will yield an error if it is expired, which you will have to remove and wait for the client to re-send a fresh token
3 - Topics is common practice, have every device listen to a 'global' topic but there is a native delay as FCM is designed for maximum output rather than time sensitivity. for that, you will need external services that specialize in high speed messages.
4 - you can invoke cloud functions to invoke other firebase services, even the rest API and onTrigger listeners on a database are valid
5 - FCM is great, but it's not the best as it was created as a general solution. a combination of different CM services is recommended, especially if you have time-sensitive needs. but they do come at a cost while FCM is free.
I am testing an app using firebase push notifications using appium.
Now I want to send a test notification to the app. For this I need the fcm token from the app.
The app is a production build, it does not display or expose the fcm token anywhere, why should it?
But of course I need to access the token from my appium tests. Is there a good way to extract data normally not exposed using adb? Or some other mechanism on how to get the fcm token without displaying it on a label in the app?
Appium itself is actually using adb to get data related to the app.
If you cannot get fcm token via adb (for security reasons its shouldn't be possible), there is no way Appium can get it.
You may look into Firebase API to check if you can get token from service side. Still the best option will be to use test build where you modified app to expose token.
I want to develop a website that will be able to send push notifications to a mobile application that would be able to run on both android and iOS.
For the last couple of years, I am working as a web developer so developing the website is not something that I am worried about, but I have never developed a mobile application before, the mobile app would only receive notifications from the website so the main functionality would be in the website.
Can anyone suggest me what the best approach is and what I have to learn to be able to do this?
Thank you in Regards
I guess, you have 2 options.
You can either use Firebase FCM
https://firebase.google.com/docs/cloud-messaging/
or use a third party which is called OneSignal
https://onesignal.com/.
If you are looking for an easier way then I recommend using OneSignal instead. You just need to define API Key in your build.gradle and initialize OneSignal in onCreate().
The best approach, in my opinion, would be to use firebase (https://firebase.google.com/products/cloud-messaging/). I think it is better because it is a unique framework for both ios and android and you don't need to worry about the user device when sending the message(you could build an interface in your backend code to handle this but why doing something that already exists and it is free).
The flow is something like this:
on the first start the app(either ios or android) must send its firebase ID to your server so that you can store it (simple http request will od it) and set up a listener for the incoming push messages
when you need to send a push message all you need to do is an http request and you can trigger it with js from your website. The request will contain data such as the firebase id of the receiving device(which you have previously stored)
Firebase Cloud Messaging also have some really nice features like upstream messages(push messages from the device to the server, but you need an xmpp server to listen for them) and topics to send the same notification to many users at the same time
I think the best approach would be to create a node server where the website would be running on and then use Firebase Cloud Messaging (FCM) to send notifications
EDIT: FCM supports both Android and iOS
I have an android app which i connect to my server using REST API (django rest framework)
here is a scenario(and maybe my plan):
data is sent back and forth as json
I have a user model and a task model where users are owners of some task.
Users typicaly sends a task to another user (with json similar to this: {"owner": "exampleuser", "from":"otheruser", "content":"example" ...} using POST method)
-The tasks has a boolean field "completed" and is deleted once the task is completed (using PUT or PATCH method: completed = true,)
once a new task gets created using POST method, the only way users can see any activities concerning their tasks is through an android activity that uses GET method to get a list of all the tasks owned by the user, by looking up all objects owned by the user
So my questions are:
Instead of having the user to check the app everytime. How can I use GCM to push notify the user?
How will it tell which user or device to send the push notification to?
How does GCM knows when there has been a change to tasks or when a user POST a task?
Android keeps one active connection to Google's servers, but it doesn't use much power or data, because no traffic is sent along it until something sends a GCM message to an app on your phone. There's only one connection on the phone, used by all apps: installing a new app that uses GCM doesn't add any extra load.
The first step in GCM is that a third-party server (such as an email server) sends a request to Google's GCM server. This server then sends the message to your device, through that open connection. The Android system looks at the message to determine which app it's for, and starts that app. The app must have registered with Android to use GCM, and it must have the relevant permission. When the app starts, it might create a notification straight away with the data from the message. GCM messages are very limited in size, so the app might instead open a normal connection to the third-party server to get more information (for example, downloading the headers of new emails).
The advantage of using push notifications is that apps don't have to run at regular intervals to check for new data, saving both power and data. The advantage of having a centralized mechanism like GCM is that the device only needs one open network connection and the Android GCM system is the only thing that needs to keep running, rather than each app having to stay running in the background to keep its own network connection to its own server.
As per the GCM implementation, it requires that you implement a remote server which will manage all the requests, both incoming and outgoing. You can do this simply with a web server acting as a webservice, which will get (for instance) the requests from the clients with a HTTP POST request, and process act consequently.
Instead of having the user to check the app everytime. How can I use GCM to push notify the user?
This will be managed by the server that I just described. It will know who is subscribed and who should receive the notifications.
How will it tell which user or device to send the push notification to?
Same goes here. The server, upon a subscription, should store the users in some kind of storage (a SQL database, for instance), and this way it will know who to send notifications. This implies you'll have to implement some timeout mechanism. In my case, I make clients send a dummy HTTP POST every 30 seconds. If I don't get this request from a reasonable amount of time, I consider the client timed-out and therefore I remove them from the database.
How does GCM knows when there has been a change to tasks or when a user POST a task?
Same story, it's all handled by the server. You implement the logic of what should happen upon any request.
You might want to read this: How to send location of the device on server when needed
And also this references:
Reference on Google Cloud Messaging
Android Push Notifications using Google Cloud Messaging GCM - Android Example
Google Cloud Messaging using PHP
Connection between PHP (server) and Android (client) Using HTTP and JSON
Notificaciones Push Android: Google Cloud Messaging (GCM). Implementación Cliente (Nueva Versión) (spanish)
I have an app that runs across iOS and Android. I'm working to add push notifications to that app.
At a very high level, devices register with the Apple Push Notification Service (APNS) or Google Cloud Messaging (GCM) and receive a token. They then hand that token back to the server that's in charge of sending notifications. That server, when it wants to, sends a notification to APNS or GCM and says "send this notification to the devices with these tokens".
So, my apps need to be able to securely send their tokens to my server, and delete those tokens from the server when the user no longer wants to receive notifications. It's very easy to add a simple CRUD page on the server side which handles ?create=<token>, ?delete=<token>, etc.
But what happens when someone goes to my server and starts spamming random values for ?delete=<token> — it seems like they'd be able to just delete random device tokens at will?
I've thought about the "delete" case a bit more, and I think it should be easy: the app can just send along a generated public decryption key with the initial “create this token” request. That key can be stored against the token. When the app wants to delete, it can send along the encrypted copy of the token, and the server can match the token against the decrypted copy, verifying that the app must possess the stored public keys matching private encryption key (which is a secret known only to the app).
What happens when someone starts spamming random values for ?create=<token> — do they get to just fill up my database table with fake device tokens?
I can't see an easy answer — rate limiting "create" requests from any single IP address seems to be about the best we can do without registration involved. That obviously isn't going to help us against any distributed attack.
Ideally I'd like to enable push notifications by default / without the user having to "register" or anything like that. My first thought is that each device token should be tied to a known canonical Apple ID or Google account — but how do I stop users from falsifying those? Do devices come with a certificate that I can get an authoritative public key for (in which case each device can just get a row tied to its public key)? What's the best way for me to implement authentication here?
The solution to the problem for android can be found Here. In brief it can be summarised as
You use the GoogleAuthUtil class, available through Google Play
services, to retrieve a string called an “ID Token”. You send the
token to your back end and your back end can use it to quickly and
cheaply verify which app sent it and who was using the app.
A lot of good questions here. :)
Let me try to break it down.
General thoughts
I don't think it's good idea to mix Android and iOS here. High level push notification architecture is similar between them, but that's about it.
Tokens are long (as I remember iOS token is uuid). So, there is no way to guess it by just randomly trying different values. So, I would say ?delete=<token> case is non existent.
The case of ?create=<token> is more realistic. First of all, somebody can bring your server to knees, registering millions of tokens. Also, if you are sending some sensitive information via push notification, you may don't want it to be received by non authorized app users.
Android solution
For Android it's easier.
As soon as you get a token on the server, just send a push message with some randomly generated string (store it in DB). Your application on a device will get this string and will send it with the token to the server (via second web call). And your server make sure that it will send anything to this token only after it was authenticated.
This way you rely on GCM ability to deliver messages to correct clients to make sure that authentication information (random string) is delivered to your application.
iOS solution
The problem with iOS is that push notification doesn't automatically trigger code execution, if the application is suspended or in background.
So, if you will try to do the same thing and a user accidentally exits your app, while push notification is being deliver than your app will never see it.
You can do following (the idea is basically the same as for Android, only with difference that we may need to require user interaction)
Push notification with a message "Please run my app and enter X" (where X is some random string)
This way, if your app is in background, a user will click on this message, enter X and your app will authenticated to the server.
In the case, if app is in foreground, it will get push payload and can authenticate directly.