Android 中的推送通知仅在 PhoneGap 应用程序使用节点推送通知处于前台时才有效
Push notifications in Android only work when PhoneGap app is in foreground using node-pushnotifications
在我的 PhoneGap / Cordova 应用程序(使用 Framework7
)中,我使用 <plugin name="phonegap-plugin-push" source="npm" spec="2.3.0" />
启用推送通知。在项目文件夹的根目录中,我放置了 google-services.json
文件。当用户登录我的应用程序时,设备令牌会在我的服务器上注册。接下来,我使用 node-pushnotifications
模块向这些令牌发送推送通知。
对于 iOS 设备,一切都按预期工作,但对于 Android,它仅在应用程序处于前台时才有效。当我在应用程序处于后台时发送推送通知时,似乎什么也没有发生。当应用程序打开(带回前台)时,会显示错过的通知(更准确地说,弹出消息显示 'new message has arrived',对于每个 'missed' 推送通知都是预期的应用程序处于前台模式时的行为)。
我在 Whosebug 上找到了几个相关的问题和答案,但它们并没有解决我的问题,但也许我在这些答案中遗漏了什么?例如,某处建议您需要指定一个 message
变量。但是当我将其包含在服务器代码中时,会发生解析错误。另外,根据我对 node-pushnotifications
模块说明的阅读,应该没有必要。
===
更新 1
当我使用 Firebase 控制台向 Android 设备发送推送消息时,一切都按预期工作(应用程序在后台时显示推送消息)。我怀疑原因在于 node-pushnotifications
模块。
到目前为止我尝试了什么
在 node-pushnotifications
模块设置中,我有:
- 将
icon
设置为默认值;
- 将
sound
设置为默认值;
- 将
ID
设置为SenderID
(导致失败-->未发送通知);
- 将
phonegap
设置为 false
(导致失败 --> 未发送通知)
===
更新 2
当应用程序处于后台时(但不是当应用程序关闭时),使用 node-gcm
模块可以正确发送推送通知。
===
欢迎使用 node-pushnotifications
完成这项工作的任何帮助。我很乐意在需要时提供更多解释和细节。
应用程序中的代码
基于 http://macdonst.github.io/push-workshop/
处提供的代码
注。对于 SenderID
,我使用了生成的发件人 ID 密钥 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();
服务器上的代码
基于 https://github.com/appfeel/node-pushnotifications
中提供的代码
注。对于 gcm id
,我使用了生成的服务器密钥 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
};
这是我实施的解决方案(目前在 Android 10 和 iOS 13.6 上工作和测试)
它可以帮助您轻松地在后台、前台、使用时、phone 锁定时显示自定义推送通知。
我在 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”
我使用的JS应用代码
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);
}
}
我服务器上的PHP代码
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);
在我的 PhoneGap / Cordova 应用程序(使用 Framework7
)中,我使用 <plugin name="phonegap-plugin-push" source="npm" spec="2.3.0" />
启用推送通知。在项目文件夹的根目录中,我放置了 google-services.json
文件。当用户登录我的应用程序时,设备令牌会在我的服务器上注册。接下来,我使用 node-pushnotifications
模块向这些令牌发送推送通知。
对于 iOS 设备,一切都按预期工作,但对于 Android,它仅在应用程序处于前台时才有效。当我在应用程序处于后台时发送推送通知时,似乎什么也没有发生。当应用程序打开(带回前台)时,会显示错过的通知(更准确地说,弹出消息显示 'new message has arrived',对于每个 'missed' 推送通知都是预期的应用程序处于前台模式时的行为)。
我在 Whosebug 上找到了几个相关的问题和答案,但它们并没有解决我的问题,但也许我在这些答案中遗漏了什么?例如,某处建议您需要指定一个 message
变量。但是当我将其包含在服务器代码中时,会发生解析错误。另外,根据我对 node-pushnotifications
模块说明的阅读,应该没有必要。
===
更新 1
当我使用 Firebase 控制台向 Android 设备发送推送消息时,一切都按预期工作(应用程序在后台时显示推送消息)。我怀疑原因在于 node-pushnotifications
模块。
到目前为止我尝试了什么
在 node-pushnotifications
模块设置中,我有:
- 将
icon
设置为默认值; - 将
sound
设置为默认值; - 将
ID
设置为SenderID
(导致失败-->未发送通知); - 将
phonegap
设置为false
(导致失败 --> 未发送通知)
===
更新 2
当应用程序处于后台时(但不是当应用程序关闭时),使用 node-gcm
模块可以正确发送推送通知。
===
欢迎使用 node-pushnotifications
完成这项工作的任何帮助。我很乐意在需要时提供更多解释和细节。
应用程序中的代码
基于 http://macdonst.github.io/push-workshop/
注。对于 SenderID
,我使用了生成的发件人 ID 密钥 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();
服务器上的代码
基于 https://github.com/appfeel/node-pushnotifications
注。对于 gcm id
,我使用了生成的服务器密钥 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
};
这是我实施的解决方案(目前在 Android 10 和 iOS 13.6 上工作和测试)
它可以帮助您轻松地在后台、前台、使用时、phone 锁定时显示自定义推送通知。
我在 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”
我使用的JS应用代码
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);
}
}
我服务器上的PHP代码
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);