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

时间:2015-07-03 18:27:13

标签: android cordova push-notification ionic-framework phonegap-plugins

我的Android应用在后台没有收到推送通知,而且应该根据documentation

  

Android设备上的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){

  }
}

2 个答案:

答案 0 :(得分:7)

After searching all questions in stackoverflow involving Cordova/Phonegap Push Plugin I found de source of the problem. Is written in the source code of the plugin, and it shouldn't.

The problem was that the plugin source code requires the push notification to have "message" field in order to trigger a notification while being on the background. It is especified in the GCMIntentService.java file.

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

The most helpful posts are this answer and this issue in the plugin repository. So, because I have no power over the push server action I can't have specified a "message" field in the push notifications, I had no alternative but to rewrite the source code.

So I rewrote te code like this:

@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);
            }
        }
    }
}

That way the plugin triggers a local notification if it receives a push notifications with the field "alert" instead of "message".

Then, I changed the code for the local notification itself:

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());
    }

Now the notification in the notification bar will show first the field "alert" instead of "title" and second a predefined message instead of the field "message" that doesn't exist in my push notifications.

Then I just recompile the code with:

ionic platform rm android

ionic platform add android

ionic run android

So kids, this is what happens when you write a plugin for everyone but you don't consider generic cases and you don't document well. That plugin is only useful for people with the field "message" and "title" in their push notifications.

I lost two days of my internship because of this, I took my time to write this so others won't have to.

答案 1 :(得分:0)

我有同样的问题,我通过更改一些代码行解决了。  我使用了 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插件对其进行处理。 希望对您有帮助。