Ionic/Cordova 应用在后台没有收到推送通知
Ionic/Cordova app doesn't receives push notification in the background
我的 Android 应用程序不会在后台接收推送通知,它应该根据 documentation。
An Android application on an Android device doesn't need to be running
to receive messages. The system will wake up the Android application
via Intent broadcast when the message arrives, as long as the
application is set up with the proper broadcast receiver and
permissions.
尝试不同的通知发现当且仅当通知包含属性"message"时它确实在关闭时收到推送通知,如果没有,它只是丢弃它。 (推送通知只是 JSON 个对象)。
我的通知包含所有类型的属性,包括 "alert"、"id" 和 "title",但只有 "message" 使 Android 唤醒应用程序。
不起作用的示例通知:
{ event: 'message',
from: '947957531940',
collapse_key: 'do_not_collapse',
foreground: true,
payload:
{ alert: 'Mensaje de Prueba',
title: 'Titulo Mensaje de Prueba' } }
有效的示例通知:
{ event: 'message',
from: '947957531940',
message: 'Contenido del mensaje de prueba.',
collapse_key: 'do_not_collapse',
foreground: true,
payload:
{ alert: 'Mensaje de Prueba',
title: 'Titulo Mensaje de Prueba',
message: 'Contenido del mensaje de prueba.' } }
这是 Android 设计标准还是我在我的应用程序中做错了什么?
我的应用程序是使用 Ionic 和 Cordova 开发的。
PD:请原谅我的英语。
编辑:
这是 app.js 中 .运行 模块内的 Android 推送代码,如 ng-cordova 说明指定:
if (ionic.Platform.isAndroid()){
var androidConfig = {
"senderID": "94*************",
"ecb": "window.casosPush"
};
try{
var pushNotification = window.plugins.pushNotification;
} catch (ex){
}
// Llamada en caso de exito
var successfn = function(result){
//alert("Success: " + result);
};
// Llamada en caso de error
var errorfn = function(result){
window.alert("Error: " + result);
};
// Llamada de casos de notificacion push
window.casosPush = function(notification){
switch (notification.event){
case 'registered':
if (notification.regid.length > 0){
$rootScope.data.token = notification.regid;
//alert('registration ID = ' + notification.regid);
}
break;
case 'message':
$rootScope.mensajes.unshift(notification.payload);
$localstorage.setArray('mensajes', $rootScope.mensajes);
alert(JSON.stringify(notification));
break;
case 'error':
alert('GCM error = ' + notification.msg);
break;
default:
alert('An unknown GCM event has occurred');
break;
}
};
try{
// Llamada de registro con la plataforma GCM
pushNotification.register(successfn,errorfn,androidConfig);
} catch(notification){
}
}
在 Whosebug 中搜索所有涉及 Cordova/Phonegap Push Plugin 的问题后,我找到了问题的根源。插件源码里写的,应该不是。
问题是插件源代码要求推送通知具有 "message" 字段,以便在后台触发通知。它在 GCMIntentService.java 文件中指定。
if (extras.getString("message") != null && extras.getString("message").length() != 0) {
createNotification(context, extras);
}
最有帮助的帖子是插件存储库中的这篇 answer and this issue。因此,因为我无法控制推送服务器操作,所以我无法在推送通知中指定 "message" 字段,所以我别无选择,只能重写源代码。
所以我重写了这样的代码:
@Override
protected void onMessage(Context context, Intent intent) {
Log.d(TAG, "onMessage - context: " + context);
// Extract the payload from the message
Bundle extras = intent.getExtras();
if (extras != null)
{
// if we are in the foreground, just surface the payload, else post it to the statusbar
if (PushPlugin.isInForeground()) {
extras.putBoolean("foreground", true);
PushPlugin.sendExtras(extras);
}
else {
extras.putBoolean("foreground", false);
// Send a notification if there is a message
//if (extras.getString("message") != null && extras.getString("message").length() != 0) {
if (extras.getString("alert") != null && extras.getString("alert").length() != 0) {
createNotification(context, extras);
}
}
}
}
如果插件收到带有字段 "alert" 而不是 "message" 的推送通知,那么插件会触发本地通知。
然后,我更改了本地通知本身的代码:
public void createNotification(Context context, Bundle extras)
{
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String appName = getAppName(this);
Intent notificationIntent = new Intent(this, PushHandlerActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
notificationIntent.putExtra("pushBundle", extras);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
int defaults = Notification.DEFAULT_ALL;
if (extras.getString("defaults") != null) {
try {
defaults = Integer.parseInt(extras.getString("defaults"));
} catch (NumberFormatException e) {}
}
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setDefaults(defaults)
.setSmallIcon(context.getApplicationInfo().icon)
.setWhen(System.currentTimeMillis())
//.setContentTitle(extras.getString("title"))
.setContentTitle(extras.getString("alert"))
//.setTicker(extras.getString("title"))
.setTicker(extras.getString("alert"))
.setContentIntent(contentIntent)
.setAutoCancel(true);
/*
String message = extras.getString("message");
if (message != null) {
mBuilder.setContentText(message);
} else {
mBuilder.setContentText("<missing message content>");
}
*/
// Agregado mensaje predefinido
mBuilder.setContentText("Haz clic para más información");
String msgcnt = extras.getString("msgcnt");
if (msgcnt != null) {
mBuilder.setNumber(Integer.parseInt(msgcnt));
}
int notId = 0;
try {
notId = Integer.parseInt(extras.getString("notId"));
}
catch(NumberFormatException e) {
Log.e(TAG, "Number format exception - Error parsing Notification ID: " + e.getMessage());
}
catch(Exception e) {
Log.e(TAG, "Number format exception - Error parsing Notification ID" + e.getMessage());
}
mNotificationManager.notify((String) appName, notId, mBuilder.build());
}
现在通知栏中的通知将首先显示字段 "alert" 而不是 "title" 然后是预定义的消息而不是我的字段 "message" 中不存在的推送通知。
然后我重新编译代码:
ionic platform rm android
ionic platform add android
ionic run android
所以孩子们,当您为每个人编写插件时会发生这种情况,但您不考虑一般情况并且您没有很好地记录。该插件仅对推送通知中包含字段 "message" 和 "title" 的人有用。
我因此失去了两天的实习时间,我花时间写了这篇文章,以免其他人不得不写。
你是对的@David prieto。
问题是插件源代码要求推送通知具有 "message" 字段,以便在后台触发通知。
有一种方法可以将 "message" 字段放入推送通知中,而且很简单。
具有通知数据的有效负载数组,通过 API 发送。它应该有一个 "message" 字段。所以推送通知会自动在里面有一个消息字段,它会在后台和前台被检测到。
我也遇到了同样的问题,改了几行代码就解决了。
我使用了 phonegap-plugin-push 插件并更改了这个文件。(仅适用于 android 平台)
插件文件夹 : phonegap-plugin-push/src/android/com/adobe/phonegap/push/FCMService.java
平台文件夹:android/src/com/adobe/phonegap/push/FCMService.java
您需要更改两个文件之一,这取决于您是否已添加平台。
// if we are in the foreground and forceShow is `false` only send data
if (!forceShow && PushPlugin.isInForeground()) {
Log.d(LOG_TAG, "foreground");
extras.putBoolean(FOREGROUND, true);
extras.putBoolean(COLDSTART, false);
PushPlugin.sendExtras(extras);
}
// if we are in the foreground and forceShow is `true`, force show the notification
if the data has at least a message or title
else if (forceShow && PushPlugin.isInForeground()) {
Log.d(LOG_TAG, "foreground force");
extras.putBoolean(FOREGROUND, true);
extras.putBoolean(COLDSTART, false);
showNotificationIfPossible(applicationContext, extras);
}
// if we are not in the foreground always send notification if the data has at least a message or title
else {
Log.d(LOG_TAG, "background");
extras.putBoolean(FOREGROUND, false);
extras.putBoolean(COLDSTART, PushPlugin.isActive());
showNotificationIfPossible(applicationContext, extras);
}
Here, PushPlugin.sendExtras() , this is the trigger for
localNotification and showNotificationIfPossible() is the trigger for
phone notification.
所以我把代码改成这样。
// if we are in the foreground and forceShow is `false` only send data
if (!forceShow && PushPlugin.isInForeground()) {
Log.d(LOG_TAG, "foreground");
extras.putBoolean(FOREGROUND, true);
extras.putBoolean(COLDSTART, false);
//PushPlugin.sendExtras(extras); // commented }
// if we are in the foreground and forceShow is `true`, force show the notification if the data has at least a message or title
else if (forceShow && PushPlugin.isInForeground()) {
Log.d(LOG_TAG, "foreground force");
extras.putBoolean(FOREGROUND, true);
extras.putBoolean(COLDSTART, false);
//showNotificationIfPossible(applicationContext, extras);// commented }
// if we are not in the foreground always send notification if the data has at least a message or title
else {
Log.d(LOG_TAG, "background");
extras.putBoolean(FOREGROUND, false);
extras.putBoolean(COLDSTART, PushPlugin.isActive());
//showNotificationIfPossible(applicationContext, extras); // commented
}
PushPlugin.sendExtras(extras); //added
所以我可以根据需要使用 localNotification 插件获取通知并处理它。
希望对您有所帮助。
我的 Android 应用程序不会在后台接收推送通知,它应该根据 documentation。
An Android application on an Android device doesn't need to be running to receive messages. The system will wake up the Android application via Intent broadcast when the message arrives, as long as the application is set up with the proper broadcast receiver and permissions.
尝试不同的通知发现当且仅当通知包含属性"message"时它确实在关闭时收到推送通知,如果没有,它只是丢弃它。 (推送通知只是 JSON 个对象)。
我的通知包含所有类型的属性,包括 "alert"、"id" 和 "title",但只有 "message" 使 Android 唤醒应用程序。
不起作用的示例通知:
{ event: 'message',
from: '947957531940',
collapse_key: 'do_not_collapse',
foreground: true,
payload:
{ alert: 'Mensaje de Prueba',
title: 'Titulo Mensaje de Prueba' } }
有效的示例通知:
{ event: 'message',
from: '947957531940',
message: 'Contenido del mensaje de prueba.',
collapse_key: 'do_not_collapse',
foreground: true,
payload:
{ alert: 'Mensaje de Prueba',
title: 'Titulo Mensaje de Prueba',
message: 'Contenido del mensaje de prueba.' } }
这是 Android 设计标准还是我在我的应用程序中做错了什么?
我的应用程序是使用 Ionic 和 Cordova 开发的。
PD:请原谅我的英语。
编辑:
这是 app.js 中 .运行 模块内的 Android 推送代码,如 ng-cordova 说明指定:
if (ionic.Platform.isAndroid()){
var androidConfig = {
"senderID": "94*************",
"ecb": "window.casosPush"
};
try{
var pushNotification = window.plugins.pushNotification;
} catch (ex){
}
// Llamada en caso de exito
var successfn = function(result){
//alert("Success: " + result);
};
// Llamada en caso de error
var errorfn = function(result){
window.alert("Error: " + result);
};
// Llamada de casos de notificacion push
window.casosPush = function(notification){
switch (notification.event){
case 'registered':
if (notification.regid.length > 0){
$rootScope.data.token = notification.regid;
//alert('registration ID = ' + notification.regid);
}
break;
case 'message':
$rootScope.mensajes.unshift(notification.payload);
$localstorage.setArray('mensajes', $rootScope.mensajes);
alert(JSON.stringify(notification));
break;
case 'error':
alert('GCM error = ' + notification.msg);
break;
default:
alert('An unknown GCM event has occurred');
break;
}
};
try{
// Llamada de registro con la plataforma GCM
pushNotification.register(successfn,errorfn,androidConfig);
} catch(notification){
}
}
在 Whosebug 中搜索所有涉及 Cordova/Phonegap Push Plugin 的问题后,我找到了问题的根源。插件源码里写的,应该不是。
问题是插件源代码要求推送通知具有 "message" 字段,以便在后台触发通知。它在 GCMIntentService.java 文件中指定。
if (extras.getString("message") != null && extras.getString("message").length() != 0) {
createNotification(context, extras);
}
最有帮助的帖子是插件存储库中的这篇 answer and this issue。因此,因为我无法控制推送服务器操作,所以我无法在推送通知中指定 "message" 字段,所以我别无选择,只能重写源代码。
所以我重写了这样的代码:
@Override
protected void onMessage(Context context, Intent intent) {
Log.d(TAG, "onMessage - context: " + context);
// Extract the payload from the message
Bundle extras = intent.getExtras();
if (extras != null)
{
// if we are in the foreground, just surface the payload, else post it to the statusbar
if (PushPlugin.isInForeground()) {
extras.putBoolean("foreground", true);
PushPlugin.sendExtras(extras);
}
else {
extras.putBoolean("foreground", false);
// Send a notification if there is a message
//if (extras.getString("message") != null && extras.getString("message").length() != 0) {
if (extras.getString("alert") != null && extras.getString("alert").length() != 0) {
createNotification(context, extras);
}
}
}
}
如果插件收到带有字段 "alert" 而不是 "message" 的推送通知,那么插件会触发本地通知。
然后,我更改了本地通知本身的代码:
public void createNotification(Context context, Bundle extras)
{
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String appName = getAppName(this);
Intent notificationIntent = new Intent(this, PushHandlerActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
notificationIntent.putExtra("pushBundle", extras);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
int defaults = Notification.DEFAULT_ALL;
if (extras.getString("defaults") != null) {
try {
defaults = Integer.parseInt(extras.getString("defaults"));
} catch (NumberFormatException e) {}
}
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setDefaults(defaults)
.setSmallIcon(context.getApplicationInfo().icon)
.setWhen(System.currentTimeMillis())
//.setContentTitle(extras.getString("title"))
.setContentTitle(extras.getString("alert"))
//.setTicker(extras.getString("title"))
.setTicker(extras.getString("alert"))
.setContentIntent(contentIntent)
.setAutoCancel(true);
/*
String message = extras.getString("message");
if (message != null) {
mBuilder.setContentText(message);
} else {
mBuilder.setContentText("<missing message content>");
}
*/
// Agregado mensaje predefinido
mBuilder.setContentText("Haz clic para más información");
String msgcnt = extras.getString("msgcnt");
if (msgcnt != null) {
mBuilder.setNumber(Integer.parseInt(msgcnt));
}
int notId = 0;
try {
notId = Integer.parseInt(extras.getString("notId"));
}
catch(NumberFormatException e) {
Log.e(TAG, "Number format exception - Error parsing Notification ID: " + e.getMessage());
}
catch(Exception e) {
Log.e(TAG, "Number format exception - Error parsing Notification ID" + e.getMessage());
}
mNotificationManager.notify((String) appName, notId, mBuilder.build());
}
现在通知栏中的通知将首先显示字段 "alert" 而不是 "title" 然后是预定义的消息而不是我的字段 "message" 中不存在的推送通知。
然后我重新编译代码:
ionic platform rm android
ionic platform add android
ionic run android
所以孩子们,当您为每个人编写插件时会发生这种情况,但您不考虑一般情况并且您没有很好地记录。该插件仅对推送通知中包含字段 "message" 和 "title" 的人有用。
我因此失去了两天的实习时间,我花时间写了这篇文章,以免其他人不得不写。
你是对的@David prieto。 问题是插件源代码要求推送通知具有 "message" 字段,以便在后台触发通知。
有一种方法可以将 "message" 字段放入推送通知中,而且很简单。 具有通知数据的有效负载数组,通过 API 发送。它应该有一个 "message" 字段。所以推送通知会自动在里面有一个消息字段,它会在后台和前台被检测到。
我也遇到了同样的问题,改了几行代码就解决了。 我使用了 phonegap-plugin-push 插件并更改了这个文件。(仅适用于 android 平台)
插件文件夹 : phonegap-plugin-push/src/android/com/adobe/phonegap/push/FCMService.java
平台文件夹:android/src/com/adobe/phonegap/push/FCMService.java
您需要更改两个文件之一,这取决于您是否已添加平台。
// if we are in the foreground and forceShow is `false` only send data
if (!forceShow && PushPlugin.isInForeground()) {
Log.d(LOG_TAG, "foreground");
extras.putBoolean(FOREGROUND, true);
extras.putBoolean(COLDSTART, false);
PushPlugin.sendExtras(extras);
}
// if we are in the foreground and forceShow is `true`, force show the notification
if the data has at least a message or title
else if (forceShow && PushPlugin.isInForeground()) {
Log.d(LOG_TAG, "foreground force");
extras.putBoolean(FOREGROUND, true);
extras.putBoolean(COLDSTART, false);
showNotificationIfPossible(applicationContext, extras);
}
// if we are not in the foreground always send notification if the data has at least a message or title
else {
Log.d(LOG_TAG, "background");
extras.putBoolean(FOREGROUND, false);
extras.putBoolean(COLDSTART, PushPlugin.isActive());
showNotificationIfPossible(applicationContext, extras);
}
Here, PushPlugin.sendExtras() , this is the trigger for localNotification and showNotificationIfPossible() is the trigger for phone notification.
所以我把代码改成这样。
// if we are in the foreground and forceShow is `false` only send data
if (!forceShow && PushPlugin.isInForeground()) {
Log.d(LOG_TAG, "foreground");
extras.putBoolean(FOREGROUND, true);
extras.putBoolean(COLDSTART, false);
//PushPlugin.sendExtras(extras); // commented }
// if we are in the foreground and forceShow is `true`, force show the notification if the data has at least a message or title
else if (forceShow && PushPlugin.isInForeground()) {
Log.d(LOG_TAG, "foreground force");
extras.putBoolean(FOREGROUND, true);
extras.putBoolean(COLDSTART, false);
//showNotificationIfPossible(applicationContext, extras);// commented }
// if we are not in the foreground always send notification if the data has at least a message or title
else {
Log.d(LOG_TAG, "background");
extras.putBoolean(FOREGROUND, false);
extras.putBoolean(COLDSTART, PushPlugin.isActive());
//showNotificationIfPossible(applicationContext, extras); // commented
}
PushPlugin.sendExtras(extras); //added
所以我可以根据需要使用 localNotification 插件获取通知并处理它。 希望对您有所帮助。