Ionic/Cordova应用在后台无法接收推送通知

5
我的Android应用在后台没有接收到推送通知,但根据文档,它应该可以接收到。

Android设备上的Android应用程序不需要运行即可接收消息。只要应用程序设置了正确的广播接收器和权限,当消息到达时,系统会通过Intent广播唤醒Android应用程序。

尝试不同的通知后发现,仅当通知包含"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开发。

附注:请原谅我的英语。

编辑:

这是app.js中.run模块内的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){

  }
}

你所说的“close”是什么意思?“force close”是在设置里吗?如果是,那么执行后它就再也收不到推送了。 - TeeTracker
@TeeTracker 不是强制关闭,只是在后台不活动,在屏幕上当前不活动。我非常清楚如果应用程序被强制关闭,推送通知将无法工作。 - David Prieto
你能给我展示一下你的代码吗? - cfprabhu
@cfprabhu是ng-cordova示例中的标准代码,我会更新问题。 - David Prieto
3个回答

7
在搜索所有涉及Cordova/Phonegap推送插件的stackoverflow问题后,我找到了问题的源头。它写在插件的源代码中,但不应该这样做。
问题是插件源代码要求推送通知具有“message”字段,以便在后台时触发通知。这在GCMIntentService.java文件中被指定。
if (extras.getString("message") != null && extras.getString("message").length() != 0) {
    createNotification(context, extras);
}

最有帮助的帖子是这个答案和插件存储库中的这个问题。因此,由于我对推送服务器操作没有控制权,我无法在推送通知中指定“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());
    }

现在通知栏中的通知将首先显示“警报”字段,而不是“标题”,其次是预定义的消息,而不是我推送通知中不存在的“消息”字段。
然后我只需重新编译代码:
ionic platform rm android

ionic platform add android

ionic run android

孩子们,当你为所有人编写插件时,如果你没有考虑通用情况并且没有很好地记录文档,就会发生这种情况。该插件仅适用于推送通知中具有“消息”和“标题”字段的用户。
因为这个问题,我在实习期间浪费了两天的时间,现在我花了时间写下这篇文章,希望其他人不要再犯同样的错误。

1
你不知道我为了让ionic中的通知功能正常工作而浪费了多少天时间... - helsont
是的,我知道 @enlitement。 - David Prieto
你解决了iOS的这个问题吗? - helsont
@enlitement 我还没有机会查看iOS版本,但我记得它不需要“message”属性。 - David Prieto

2
你是正确的,@David Prieto。问题在于插件源代码要求推送通知必须具有“消息”字段才能在后台触发通知。
推送通知中有一种方法可以添加“消息”字段,而且非常简单。通过API发送的包含通知数据的负载数组应该具有一个“消息”字段。这样,推送通知将自动包含一个消息字段,并且无论在后台还是前台都会被检测到。

1
我遇到了同样的问题,通过改变一些代码行来解决了。我使用了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);
  }

在这里,PushPlugin.sendExtras() 是触发本地通知的触发器,showNotificationIfPossible() 则是触发电话通知的触发器。

所以我将代码更改为以下内容。

  // 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 插件进行处理。希望这会对你有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接