In my PhoneGap / Cordova app (using Framework7
), I use the <plugin name="phonegap-plugin-push" source="npm" spec="2.3.0" />
to enable push notifications. In the root of the project folder, I have put the google-services.json
file. When users log in to my app, the device tokens are registered on my server. Next, I use the node-pushnotifications
module to send push notifications to these tokens.
For iOS devices everything works as expected, but for Android it only works when the app is in foreground. When I send push notifications when the app is in background, nothing seems to happen. When the app is opened (brought back to foreground), the notifications that have been missed are showed (more precisely, a pop up message appears that a 'new message has arrived', for each 'missed' push notification as is the expected behavior when the app is in foreground modus).
I have found several related questions and answers on StackOverflow, but they did not solve my issue, but maybe I have missed something in these answers? For example, somewhere it was suggested that you need to specify a message
variable. But when I include this in the server code, a parsing error occurs. Also, based on my reading of the instructions of node-pushnotifications
module, that should not be necessary.
===
Update 1
When I use the Firebase Console to send push messages to the Android device, everything works as expected (push messages are being shown when the app is in background). I suspect the cause lies in the node-pushnotifications
module.
What I have tried so far
In the node-pushnotifications
module settings, I have:
icon
to default;sound
to default;ID
to SenderID
(results in failure --> notification not sent);phonegap
to false
(results in failure --> notification not sent)===
Update 2
Push notifications are correctly delivered using the node-gcm
module when the app is in background (but not when the app is closed).
===
Any help is appreciated to make this work using node-pushnotifications
is welcome. I am happy to give more explanations and details when needed.
Code in the app
Based on the code provided at http://macdonst.github.io/push-workshop/
Note. For the SenderID
, I used the sender id key generated in/by Firebase.
var message = {
// Application Constructor
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
document.getElementById("toggleBtn").addEventListener('click', this.toggle, false);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicitly call 'app.receivedEvent(...);'
onDeviceReady: function() {
message.push = PushNotification.init({
"android": {
"senderID": "**********"
},
"ios": {
"sound": true,
"vibration": true,
"badge": false
},
"windows": {}
});
message.push.on('registration', function(data) {
var oldRegId = localStorage.getItem('registrationId');
if (oldRegId !== data.registrationId) {
// Save new registration ID
localStorage.setItem('registrationId', data.registrationId);
// Post registrationId to your app server as the value has changed
var uname= window.localStorage.getItem('uname');
var pwd= window.localStorage.getItem('pwd');
var devicetoken=localStorage.getItem('registrationId');
var dataString="uname="+uname+"&pwd="+pwd+"&devicetoken="+devicetoken+"&updateregistration=yes";
$.ajax({
type:"POST",
url:"******************", data: dataString,
crossDomain: true,
cache: false,
success:function(data)
{
}
});
}
});
message.push.on('error', function(e) {
console.log("push error = " + e.message);
});
message.push.on('notification', function(data) {
console.log('notification event');
app.dialog.alert("You have a new message", function () {
app.views.main.router.navigate('/messages/');
});
});
}
};
message.initialize();
Code on the server
Based on the code provided at https://github.com/appfeel/node-pushnotifications
Note. For the gcm id
, I used the server key generated in/by Firebase.
// Step 1: configure push notification settings
var PushNotifications = require('node-pushnotifications')
const settings = {
gcm: {
id: '*******',
phonegap: true, // phonegap compatibility mode, see below (defaults to false)
},
apn: {
token: {
key: '*******', // optionally: fs.readFileSync('./certs/key.p8')
keyId: '*******',
teamId: '*******',
},
production: true // true for APN production environment, false for APN sandbox environment,
//...
},
isAlwaysUseFCM: false, // true all messages will be sent through node-gcm (which actually uses FCM)
};
const push = new PushNotifications(settings);
// Step 2 create the notification
const data = {
title: 'New push notification', // REQUIRED for Android
topic: '**********', // REQUIRED for iOS (apn and gcm)
/* The topic of the notification. When using token-based authentication, specify the bundle ID of the app.
* When using certificate-based authentication, the topic is usually your app's bundle ID.
* More details can be found under https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns
*/
body: 'Powered by AppFeel',
custom: {
sender: 'AppFeel',
},
priority: 'high', // gcm, apn. Supported values are 'high' or 'normal' (gcm). Will be translated to 10 and 5 for apn. Defaults to 'high'
collapseKey: '', // gcm for android, used as collapseId in apn
contentAvailable: true, // gcm, apn. node-apn will translate true to 1 as required by apn.
delayWhileIdle: true, // gcm for android
restrictedPackageName: '', // gcm for android
dryRun: false, // gcm for android
icon: '', // gcm for android
image: '', // gcm for android
style: '', // gcm for android
picture: '', // gcm for android
tag: '', // gcm for android
color: '', // gcm for android
clickAction: '', // gcm for android. In ios, category will be used if not supplied
locKey: '', // gcm, apn
locArgs: '', // gcm, apn
titleLocKey: '', // gcm, apn
titleLocArgs: '', // gcm, apn
retries: 1, // gcm, apn
encoding: '', // apn
badge: 2, // gcm for ios, apn
sound: 'ping.aiff', // gcm, apn
android_channel_id: '', // gcm - Android Channel ID
notificationCount: 0, // fcm for android. badge can be used for both fcm and apn
alert: { // apn, will take precedence over title and body
title: 'title',
body: 'body'
// details: https://github.com/node-apn/node-apn/blob/master/doc/notification.markdown#convenience-setters
},
silent: false, // apn, will override badge, sound, alert and priority if set to true
/*
* A string is also accepted as a payload for alert
* Your notification won't appear on ios if alert is empty object
* If alert is an empty string the regular 'title' and 'body' will show in Notification
*/
// alert: '',
launchImage: '', // apn and gcm for ios
action: '', // apn and gcm for ios
category: '', // apn and gcm for ios
// mdm: '', // apn and gcm for ios. Use this to send Mobile Device Management commands.
// https://developer.apple.com/library/content/documentation/Miscellaneous/Reference/MobileDeviceManagementProtocolRef/3-MDM_Protocol/MDM_Protocol.html
urlArgs: '', // apn and gcm for ios
truncateAtWordEnd: true, // apn and gcm for ios
mutableContent: 0, // apn
threadId: '', // apn
pushType: undefined, // apn. valid values are 'alert' and 'background' (https://github.com/parse-community/node-apn/blob/master/doc/notification.markdown#notificationpushtype)
expiry: Math.floor(Date.now() / 1000) + 28 * 86400, // unit is seconds. if both expiry and timeToLive are given, expiry will take precedence
timeToLive: 28 * 86400,
headers: [], // wns
launch: '', // wns
duration: '', // wns
consolidationKey: 'my notification', // ADM
};
This is the solution I implemented (currently working and tested on Android 10 and iOS 13.6)
It can help you to easily shows customized push notifications on background, foreground, when in use, when the phone is locked.
My configuration in CLI:
cordova -v
7.1.0
cordova platforms
android 8.0.0
ios 4.5.5
cordova plugins
phonegap-plugin-push 2.3.0 "PushPlugin"
phonegap-plugin-multidex 1.0.0 "Multidex"
The JS app code I am using
document.addEventListener("deviceready", registrarDevice, false);
function registrarDevice() {
try {
var push = PushNotification.init({
android: {
senderID: "YOUR_SENDER_ID_FROM_FIREBASE"
},
browser: {
pushServiceURL: 'http://push.api.phonegap.com/v1/push'
},
ios: {
alert: "true",
badge: "true",
sound: "true"
},
windows: {}
});
push.on('registration', function (data) {
// data.registrationId
console.log(data);
});
push.on('notification', function (data) {
console.log(data);
// data.message,
// data.title,
// data.count,
// data.sound,
// data.image,
// data.additionalData
});
push.on('error', function (e) {
// e.message
console.log(e);
});
} catch (err) {
console.log("Error registrarDevice: ", err.message);
}
}
The PHP code on my server
class FCM {
function __construct() {
}
public function send_push_notification($registatoin_ids, $notification, $device_type) {
$url = 'https://fcm.googleapis.com/fcm/send';
if($device_type == "Android"){
$fields = array(
'to' => $registatoin_ids,
'data' => $notification
);
} else {
$fields = array(
'to' => $registatoin_ids,
'notification' => $notification
);
}
// Your Firebase Server API Key
$apikey = "YOUR_FIREBASE_SERVER_API_KEY";
$headers = array('Authorization:key='.$apikey,'Content-Type:application/json');
// Open curl connection
$ch = curl_init();
// Set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
if ($result === FALSE) {
die('Curl failed: ' . curl_error($ch));
}
curl_close($ch);
}
}
function notificaciones_android_base($xdevice_destino,$xtitulo,$xtexto){
$NotificationArray= array();
$NotificationArray["body"] = $xtexto;
$NotificationArray["title"] = $xtitulo;
$NotificationArray["sound"] = "default";
$NotificationArray["type"] = 1;
$fcm = new FCM();
$retresult = $fcm->send_push_notification($xdevice_destino, $NotificationArray, "Android");
return $retresult;
}
$info_test="Greetings folks!, Testing de push message :-)";
echo "<br>".notificaciones_android_base("YOUR_DEVICE_ID","NotificationTitle2021",$info_test);