Ionic/Cordova 应用程序不会在后台收到推送通知

Posted

技术标签:

【中文标题】Ionic/Cordova 应用程序不会在后台收到推送通知【英文标题】:Ionic/Cordova app doesn't receives push notification in the background 【发布时间】:2015-09-21 15:09:54 【问题描述】:

我的 android 应用没有在后台接收推送通知,它应该根据documentation。

无需在 Android 设备上运行 Android 应用程序 接收消息。系统会唤醒安卓应用 在消息到达时通过 Intent 广播,只要 应用程序设置有适当的广播接收器和 权限。

尝试不同的通知发现当且仅当通知包含属性“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中.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)

  

【问题讨论】:

你的“关闭”是什么意思?设置中的“强制关闭”?如果是,那么以后就不会再推送了。 @TeeTracker 否,不是强制关闭,只是未激活,在后台,当前在屏幕中未激活。我很清楚,如果应用程序被强制关闭,推送通知将不起作用。 你能告诉我你的代码吗? @cfprabhu 是来自 ng-cordova 示例的标准代码,我会更新问题。 【参考方案1】:

在 *** 中搜索所有涉及 Cordova/Phonegap Push Plugin 的问题后,我找到了问题的根源。是写在插件的源代码里的,不应该的。

问题在于插件源代码要求推送通知具有“消息”字段,以便在后台触发通知。它在 GCMIntentService.java 文件中指定。

if (extras.getString("message") != null && extras.getString("message").length() != 0) 
    createNotification(context, extras);

最有用的帖子是插件存储库中的 answer 和 issue。所以,因为我对推送服务器操作没有权力,我不能在推送通知中指定“消息”字段,所以我别无选择,只能重写源代码。

所以我重写了这样的代码:

@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

所以孩子们,当你为每个人编写一个插件但你没有考虑通用案例并且你没有很好地记录时,就会发生这种情况。该插件仅对推送通知中包含“消息”和“标题”字段的人有用。

因此我失去了两天的实习时间,我花时间写这篇文章,这样其他人就不用写了。

【讨论】:

你不知道我已经失去了多少天试图让通知在 ionic 中工作...... 是的,我知道@enlitement 你找到解决这个问题的 ios 了吗? @enlitement 我还没有机会查看 iOS 版本,但我记得它不需要“消息”属性。【参考方案2】:

你是对的@David prieto。 问题是插件源代码要求推送通知具有“消息”字段,以便在后台触发通知。

有一种方法可以将“消息”字段放入推送通知中,而且很简单。 具有通知数据的有效负载数组,通过 API 发送。它应该有一个“消息”字段。所以推送通知会自动在其中包含一个消息字段,它会在后台和前台被检测到。

【讨论】:

【参考方案3】:

我有同样的问题,我通过更改一些代码行解决了。 我使用 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(),这是触发 localNotification 和 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 插件获取通知并对其进行处理。 希望这会对你有所帮助。

【讨论】:

以上是关于Ionic/Cordova 应用程序不会在后台收到推送通知的主要内容,如果未能解决你的问题,请参考以下文章

Ionic Cordova:Push Notification 插件 onMessage 接收消息。

在后台获取 Ionic/Cordova 应用程序的位置

ionic + cordova 插件和后台模式

来自 http url 的 Ionic 3 (cordova) 应用程序不会作为应用程序打开,但它会在浏览器中打开

当应用不在前台时,Ionic / Cordova 触发应用操作

Cordova-res 未安装在 ionic cordova