I'm trying to use Azure mobile services to send push notifications. I got it working but currently it sends to all devices that use the application key. I realise that in the gcm.push.send() function I have to give a tag instead of null if i want to send it to individuals or groups.
I want to send it only to the current user. The user who calls the insert. I tried putting in the users gcm registration id but this does not work.
I saw examples of people registering their tags like this (in push->edit script):
exports.register = function (registration, registrationContext, done) {
var userId = registrationContext.user.userId;
registration.tags.push(userId);
done();
};
However im not using authentication so my user variable is undefined. All ive got is a unique identifier in my item table (item.id) and the registration id (item.regid). How can I get my tag working? This is my insert :
function insert(item, user, request) {
console.log("Registration ID -> " + item.regid);
var payload = {
"data": {
"message": "notification added"
}
};
request.execute({
success: function() {
// If the insert succeeds, send a notification.
push.gcm.send(item.regid, payload, {
success: function(pushResponse) {
console.log("Sent push:", pushResponse, payload);
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
request.respond(500, { error: pushResponse });
}
});
},
error: function(err) {
console.log("request.execute error", err)
request.respond();
}
});
}
Notification Hubs does not have the ability to send to a specific device right now.
The mechanism for simulate this is through the registration process and tags. Use the Notification Hubs API directly. When you register a device, register to listen with a tag that is appropriate to the device or user. For example, register to listen to tags USER-userid and DEVICE-deviceid.
Then, when you want to send to a specific device, send to DEVICE-deviceid and if you want to send to all devices that are registered to a specific user, you can send to USER-userid; obviously, replace the userid and deviceid with the appropriate values.
You can find out more about tags here: https://msdn.microsoft.com/library/azure/dn530749.aspx
If you want to send notification to specific user you must register them with unique tag or unique identifier as Adrian hall in previous answer described,I agree with him.As unique identifier in Android you can use DeviceId and in Ios identifierForVendor they are unique and they never change.
Related
i do not get any notification from firebase but when i test with Pusher app i get the notification.
these are my steps i have Done. help me if i have done something wrong.
1_ add notificationService as below.
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: #escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
// Modify the notification content here...
bestAttemptContent.title = "hello"
bestAttemptContent.body = "this is test"
contentHandler(bestAttemptContent)
}
}
}
2 _ set notificationCenter delegate to self in app delegate
Messaging.messaging().delegate=self
UNUserNotificationCenter.current().delegate = self
3_ device token for sending notification (i store this to server)
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")
let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
i send this FCMToken to server Side(java,spring boot)
4_ i have enabled push notification in Capabilities
5_ i have added .p12 file in cloud messaging of project settings in firebase console but i have big question for this !???? should i login to firebase with my server's account ? or make an account for my self ?? because i have created one for my self.
some tips :
we are a team like server side(JAVA). web , android and ios
which this push notification is working on android but not on ios.
i think i'm doing something in a wrong way.
thank you for reading this topic and helping me out.
Here is the steps to cross check your issue,
Notification Capabilities has to be enabled.
Certificate you created on apple member center should enable the push
notification
In firebase console go to settings -> project settings -> cloud messaging -> check the server key
This key and the key what you gave to you server team should be same
Check APNs Authentication Key or APNs Certificates added or not.
If you are using APNs Certificates, that should be same that you generated in the appId in the member center
get the fcm token from the xcode console -> go to firebase console -> grow -> cloud messaging -> new notification
-> and try test on device. if you receive notification client side (device) has no issues. if not server side has to double check the server key.
Add your googleServiceInfo.plist to your project. add the reversed key in your app info.
in Appdelegate, configure your firebase
FirebaseApp.configure()
Update, As per your question in the comment, am updating this question.
To make use of NotificationService Extension, you notification must include mutable-content property in the notification payload. using fcm api you can do that. put these in the post man,
https://fcm.googleapis.com/fcm/send
in the headers, add your server key (you can get this from your firebase console)
in the body add this payload to fire notification. this will trigger your Notification Service Extension.
{
"notification": {
"title": "1",
"body": "",
"click_action": "",
"icon": "",
"mutable_content": true,
"content_available": true
},
"registration_ids":["add your fcm token"],
"data": {}
}
As per the tutorial:
https://code.tutsplus.com/tutorials/ios-10-notification-service-extensions--cms-27550
I'm trying to find out how to push proper notifications using Codename One servers. I'd like to send notifications which basically look like LocalNotifications - with title, body, badge etc.
However in the documentation for push servers there seems to be just one field concerning the notification payload:
body - the body of the message.
Q1: How to push(server side through Codename One server) and display(Codename One app) a notification with title and body from the server?
I'd like be able to send and receive custom data in the payload too, e.g. reference to some app content which should be opened in the app when opening the app "from" that particular push notification.
Q2: Can I send basically anything as a notification body, even my own JSON?
In the Codename One API there is this callback interface PushCallback, specifically method void push(String value). Is this callback intended exactly for the purpose of "pre-processing/parsing" of the notification payload just before displaying it as a LocalNotification?
Thanks.
There are various types of push messages you can send in Codename One, namely 0,1,2,3,4,5,100, and 101.
If you require the title and the body, set your push type to 4 and separate your title and body with ; in your payload.
If you require a push with some hidden content which you can use to manipulate your app in the background, go for push type 3. Separate the visible and hidden payloads with ;. The hidden section is where you put your JSON string, just ensure the vissible message doesn't start with { or [. A php payload example will look something like this:
$vissibleMsg = "Cum ut quia delectus libero hic.";
$jsonString = json_encode(array("action" => "openMainForm", "id" => "1", "message" => $vissibleMsg));
$payload = $vissibleMsg . ";" . $jsonString;
And in your push(String value), read the hidden JSON content like this:
#Override
public void push(String value) {
Display.getInstance().callSerially(() -> {
if (value.startsWith("{") || value.startsWith("[")) {
try {
JSONObject response = new JSONObject(value);
switch (response.getString("action")) {
case "openMainForm":
//do whatever you want here
break;
default:
//perform default action here
break;
}
} catch (JSONException err) {
Log.e(err);
}
}
});
}
If you require a hidden content and a visible content with title and body, then you will have to send the push twice using type 2 and type 4 respectively, based on the link I shared above.
I am thinking about keeping all registration ids(push token) in DB and sending notifications to user from iPhone. I tried something like this but did not get any notification.
func sendPNMessage() {
FIRMessaging.messaging().sendMessage(
["body": "hey"],
to: TOKEN_ID,
withMessageID: "1",
timeToLive: 108)
}
What I am doing wrong or maybe it is impossible at all?
Currently it's not possible to send messages from the application itself.
You can send messages from the Firebase Web Console, or from a custom server using the server-side APIs.
What you might want to do is to contact a server (like via http call) and that server will send the message to the user.
This way ensure that the API-KEY of the server is protected.
PS: the sendMessage(..) api is called upstream feature, and can be used to send messages from your app to your server, if you server has an XMPP connection with the FCM server.
Yes you can send push notification through Firebase.Please make sure do NOT include the server-key into your client. There are ways "for not so great people" to find it and do stuff... The Proper way to achieve that is for your client to instruct your app-server to send the notification.
You have to send a HTTP-Post to the Google-API-Endpoint.
You need the following headers:
Content-Type: application/json
Authorization: key={your_server_key}
You can obtain your server key within in the Firebase-Project.
HTTP-Post-Content: Sample
{
"notification": {
"title": "Notification Title",
"text": "The Text of the notification."
},
"project_id": "<your firebase-project-id",
"to":"the specific client-device-id"
}
Google Cloud Functions make it now possible send push notifications from device-to-device without an app server.
From the Google Cloud Functions documentation:
Developers can use Cloud Functions to keep users engaged and up to
date with relevant information about an app. Consider, for example, an
app that allows users to follow one another's activities in the app.
In such an app, a function triggered by Realtime Database writes to
store new followers could create Firebase Cloud Messaging (FCM)
notifications to let the appropriate users know that they have gained
new followers.
Example:
The function triggers on writes to the Realtime Database path where followers are stored.
The function composes a message to send via FCM.
FCM sends the notification message to the user's device.
Here is a demo project for sending device-to-device push notifications with Firebase and Google Cloud Functions.
Diego's answer is very accurate but there's also cloud functions from firebase it's very convenient to send notifications in every change in the db. For example let's say you're building chat application and sending notification in every new follower change.
This function sample is very good example.
For more information about cloud functions you can check official docs.
I have an app that has a "send feedback to developer" section. I also have a User collection in my firestore database. When a user logs into the app, I have that Users data update their FCM token with the following code in my SceneDelegate.swift:
import Firebase
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
authListener = Auth.auth().addStateDidChangeListener({ (auth, user) in
Auth.auth().removeStateDidChangeListener(self.authListener!)
if user != nil {
DispatchQueue.main.async {
let docRef = Firestore.firestore().collection("User").document((user?.email)!)
docRef.getDocument { (snapshot, error) in
guard let snapshot = snapshot else {return}
Messaging.messaging().token { token, error in
if let error = error {
print("Error fetching FCM registration token: \(error)")
} else if let token = token {
docRef.updateData(["FCMtoken":token])
print("FCM registration token: \(token)")
}
}
}
}
}
})
guard let _ = (scene as? UIWindowScene) else { return }
}
then in my feedback view controller i have this code to send my specific device (but you can look up/fetch which specific device you want in your database where the FCMtoken is stored where i have INSERT-DEVICE-TOKEN-HERE). The url to send to is "https://fcm.googleapis.com/fcm/send" and you can find YOUR-APP-FCM-KEY by going to your project settings in firebase, going to cloud messaging tab and its the server key.
func sendMePushNotification() {
let token = "INSERT-DEVICE-TOKEN-HERE"
if let url = URL(string: "https://fcm.googleapis.com/fcm/send") {
var request = URLRequest(url: url)
request.allHTTPHeaderFields = ["Content-Type":"application/json", "Authorization":"key=YOUR-APP-FCM-KEY"]
request.httpMethod = "POST"
request.httpBody = "{\"to\":\"\(token)\",\"notification\":{\"title\":\"Feedback Sent!\",\"body\":\"\(self.feedbackBox.text!)\",\"sound\":\"default\",\"badge\":\"1\"},\"data\": {\"customDataKey\": \"customDataValue\"}}".data(using: .utf8)
URLSession.shared.dataTask(with: request) { (data, urlresponse, error) in
if error != nil {
print("error")
} else {
print("Successfully sent!.....")
}
}.resume()
}
}
Use onesignal,you can send device to notifications or device to segments ,it can work with firebase in this way
Use onesignal functions to create a specific id,save it in a firebase database ,then when the id can be put in another function that is used to send a notification
Notes: 1-i am using it in my apps with firebase works perfectly
2-i can submit that code,just someone comments so i can find this answer
(When I say "App" I am only talking about Android, I'm not gonna even try to deal with Apple)
So I have a website that I'd like to develop an Android app for. All I need it to do is show the website(it'll change some styling if being accessed from the app), which I can do just fine.
I use Intel XDK, which works great. But the notification options it offers seems to be just mass-notification stuff, not individualized.
All I want to do is be able to tell users when they get a notification from my website(like a message from another user).
I've looked all over the place for hours and hours and can't find anything useful. There are a ton of extremely complicated Java codes and tutorials, but I don't even know Java. I'm solely a web developer and all I want is an app that makes it easier for users to check the website.
I'm hoping there is some Java file out there that I can send data to somehow that will allow me to create and delete push notifications on Android systems. Maybe a HTML5 library or JS function, I dunno.
I simply can't seem to implement it myself, and I'm definitely not going to learn an entire dying language just for one basic thing that should be simple to do. Anything you guys can provide would be greatly appreciated. Optimally I would like to get a Java file I can download and put into my app that gives a notification, then I can edit it to say what I need it to or whatever(I also would really like a way to make the notification go away[in case the user sees it on another device before seeing it on the phone] ). I would also need to know how to call onto this Java file, make it check for notifications on the server or whatever.
I know this is all very nooby stuff, but I run an independent website and simply don't have the time to learn all this stuff when my needs are so basic. Thanks in advance.
You can use appMobi for push messaging, see documentation at http://docs.appmobi.com/index.php/push-messages/pushjsapi/. You can setup your appMobi account in the Services tab of the Intel XDK.
//Check if user is registered
var onDeviceReady=function() {
//See if the push user exists already
//You can send any unique user id and password.
AppMobi.notification.checkPushUser(AppMobi.device.uuid, AppMobi.device.uuid);
};
document.addEventListener("appMobi.device.ready",onDeviceReady,false);
//if user is not registered, register them
var isUserAdded = false;
var notificationsRegistered=function(event) {
if(event.success === false) {
if (!isUserAdded) {
isUserAdded= true;
AppMobi.notification.addPushUser(AppMobi.device.uuid,
AppMobi.device.uuid,
'no#email.com');
return;
}
AppMobi.notification.alert("Notifications Failed: " + event.message,
"My Message","OK");
return;
}
var msg = event.message || 'success';
AppMobi.notification.alert("Notifications Enabled: " + msg,
"My Message","OK");
};
document.addEventListener("appMobi.notification.push.enable",
notificationsRegistered,false);
//when push message event is found get notification
var receivedPush = function(){
var myNotifications=AppMobi.notification.getNotificationList();
//It may contain more than one message, so iterate over them
var len=myNotifications.length;
if(len > 0) {
for(i=0; i < len; i++) {
msgObj=AppMobi.notification.getNotificationData(myNotifications[i]);
try{
if(typeof msgObj == "object" && msgObj.id == myNotifications[i]){
AppMobi.notification.alert(msgObj.msg + "\n" + msgObj.data
+ "\n" + msgObj.userkey,"pushMobi Message","OK");
//Always delete messages after they are shown
AppMobi.notification.deletePushNotifications(msgObj.id);
return;
}
AppMobi.notification.alert("Invalid Message Object: " + i,
"My Message","OK");
}catch(e){
AppMobi.notification.alert("Caught Exception For: " + msgObj.id,
"My Message","OK");
AppMobi.notification.deletePushNotifications(msgObj.id);
}
}
}
};
document.addEventListener("appMobi.notification.push.receive", receivedPush, false);
//send a push notification from your website
AppMobi.notification.sendPushNotification(myAppMobiUserID,"new website blog posted!",{});
document.addEventListener("appMobi.notification.push.send",updateNotificationEvent,false);
var updateNotificationEvent=function(event)
{
if(event.success==false)
{
alert("error: " + event.message)
}
else
{
alert("success");
}
}
You can also use Parse.com APIs but I don't believe the subscribe to channel JavaScript API is fully flushed out last I checked, see https://www.parse.com/docs/push_guide#top/JavaScript.
Parse.initialize("YOUR KEY", "HERE");
// Save the current Installation to Parse.
ParseInstallation.getCurrentInstallation().saveInBackground();
You can then send push notifications through the Web Console, or on your website using:
//The following code will push the alert to the "Winterhawks" and "Oil Kings" channels.
Parse.Push.send({
channels: [ "Winterhawks", "Oil Kings" ],
data: {
alert: "The Winterhawks won against the Oil Kings!"
}
}, {
success: function() {
// Push was successful
},
error: function(error) {
// Handle error
}
});
Subscribe to channels is not yet implemented for JavaScript as far as I know so you'll have to use REST or native APIs.
As the question says that How to find out when does the registration ID has become invalid in GoogleCloudMessaging API?
I already read the answers on few questions on similar topic: Do GCM registration id's expire? and Google Coud Mesaging (GCM) and registration_id expiry, how will I know? . The issue with those question is that the answers there are for C2DMor old GCM API which used GCMRegistrar instead of GoogleCloudMessaging API. The previous two methods have been depreciated.
I'll try to break my confusion/question stepwise:
1) Under the heading Enable GCM, in the second point it says:
Google may periodically refresh the registration ID, so you should design your Android application with the understanding that the com.google.android.c2dm.intent.REGISTRATION intent may be called multiple times. Your Android application needs to be able to respond accordingly.
The registration ID lasts until the Android application explicitly unregisters itself, or until Google refreshes the registration ID for your Android application. Whenever the application receives a com.google.android.c2dm.intent.REGISTRATION intent with a registration_id extra, it should save the ID for future use, pass it to the 3rd-party server to complete the registration, and keep track of whether the server completed the registration. If the server fails to complete the registration, it should try again or unregister from GCM.
2) Now, if that's the case then I should handle the intent in a BroadcastReceiver and send the register() request again to get a new registration ID. But the issue is that on the same page under heading ERROR_MAIN_THREAD, it says that:
GCM methods are blocking. You should not run them in the main thread or in broadcast receivers.
3) I also understand that there are other two scenarios when the registration ID changes( as mentioned under Advanced Topics under heading Keeping the Registration State in Sync):
Application update and Backup&restore. I am already handling them on opening of the app.
4) In GCMRegistrar API, inside GCMBaseIntentService, there used to be a callback onRegistered() method, which got called when the device got registered. Here I used to persist the registration ID and send to 3rd party servers.
But, now How should I handle the updation or renewal of the registration ID, persist it and send it to 3rd party server?
It might be that either I am getting confused by reading all of it or I am missing something. I would be really thankful for your help.
Update
Even on Handling registration ID changes in Google Cloud Messaging on Android thread, there is no mentioning of how to handle the periodic refreshing of ID by Google?
I am giving a way as What I implemented in my application
#Override
protected void onRegistered(Context context, String registrationId) {
Log.i(TAG, "Device registered: regId = " + registrationId);
//displayMessage(context, getString(R.string.gcm_registered));
//ServerUtilities.register(context, registrationId);
//1. Store this id to application Prefs on each request of device registration
//2. Clear this id from app prefs on each request of device un-registration
//3. Now add an if check for new registartion id to server, you can write a method on server side to check if this reg-id matching for this device or not (and you need an unique identification of device to be stored on server)
//4. That method will clear that if id is matching it meanse this is existing reg-id, and if not matching this is updated reg-id.
//5. If this is updated reg-id, update on server and update into application prefs.
}
You can do like this also
if reg_id exists_into prefrences then
if stored_id equals_to new_reg_id then
do nothing
else
say server to reg_id updated
update prefrences with new id
end if
else
update this id to application prefs
say server that your device is registered
end if
But problem arises when, user clears the application data and you will loose the current reg-id.
Update for new API example Credits goes to Eran and His Answer Handling registration ID changes in Google Cloud Messaging on Android
Google changed their Demo App to use the new interface. They refresh the registration ID by setting an expiration date on the value persisted locally by the app. When the app starts, they load their locally stored registration id. If it is "expired" (which in the demo means it was received from GCM over 7 days ago), they call gcm.register(senderID) again.
This doesn't handle the hypothetical scenario in which a registration ID is refreshed by Google for an app that hasn't been launched for a long time. In that case, the app won't be aware of the change, and neither will the 3rd party server.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mDisplay = (TextView) findViewById(R.id.display);
context = getApplicationContext();
regid = getRegistrationId(context);
if (regid.length() == 0) {
registerBackground();
}
gcm = GoogleCloudMessaging.getInstance(this);
}
/**
* Gets the current registration id for application on GCM service.
* <p>
* If result is empty, the registration has failed.
*
* #return registration id, or empty string if the registration is not
* complete.
*/
private String getRegistrationId(Context context) {
final SharedPreferences prefs = getGCMPreferences(context);
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
if (registrationId.length() == 0) {
Log.v(TAG, "Registration not found.");
return "";
}
// check if app was updated; if so, it must clear registration id to
// avoid a race condition if GCM sends a message
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion || isRegistrationExpired()) {
Log.v(TAG, "App version changed or registration expired.");
return "";
}
return registrationId;
}
/**
* Checks if the registration has expired.
*
* <p>To avoid the scenario where the device sends the registration to the
* server but the server loses it, the app developer may choose to re-register
* after REGISTRATION_EXPIRY_TIME_MS.
*
* #return true if the registration has expired.
*/
private boolean isRegistrationExpired() {
final SharedPreferences prefs = getGCMPreferences(context);
// checks if the information is not stale
long expirationTime =
prefs.getLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, -1);
return System.currentTimeMillis() > expirationTime;
}
Just to add to Pankaj's answer:
This(the example on getting started documents by Google) doesn't handle the hypothetical scenario in which a registration ID is
refreshed by Google for an app that hasn't been launched for a long
time. In that case, the app won't be aware of the change, and neither
will the 3rd party server.
Its true that the example on Getting
started documentation does not handle that case. So the developer
need to handle himself.
Also the answer says that They refresh the registration ID by setting an expiration date on the value persisted locally by the app. When the app starts, they load their locally stored registration id. If it is "expired" they call gcm.register(senderID) again.
The issue is that the seven days local expiry of the registration ID in the sample is to avoid the scenario where the device sends the
registration to the 3rd party server but the server loses it. It does
not handle the refreshing of the ID from Google servers.
The second point under the heading Enable GCM on Architectural
Overview page, it says:
Note that Google may periodically refresh the registration ID, so
you should design your Android application with the understanding
that the com.google.android.c2dm.intent.REGISTRATION intent may be
called multiple times. Your Android application needs to be able to
respond accordingly.
So, for handling that you should have a Broadcast Listener which
could handle com.google.android.c2dm.intent.REGISTRATION intent,
which Google send to the app when it has to refresh the registration
ID.
There is another part of the question which states about the problem is that inside the Broadcast Listener I cannot call register the for Push ID again. This is because the
documentation says:
GCM methods are blocking. You should not run them in the main thread or in broadcast receiver.
I think that issue is completely different from the statement. When you register a broadcast receiver, it will have an Intent which will contain the new registration ID from Google. I DON'T need to call gcm.register() method again in the Broadcast listener.
Hope this helps someone understand how to handle the renewal of registration ID.