简体   繁体   English

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

[英]Ionic/Cordova app doesn't receives push notification in the background

My Android app doesn't receive push notifications in the background and it should according to the documentation . 我的Android应用程序在后台没有收到推送通知,它应该根据文档

An Android application on an Android device doesn't need to be running to receive messages. Android设备上的Android应用程序无需运行即可接收消息。 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. 只要应用程序设置了正确的广播接收器和权限,系统就会在消息到达时通过Intent广播唤醒Android应用程序。

Trying different notifications discovered that it does receives the push notifications while it is closed if and only if the notifications contains the attribute "message" , if not, it just discards it. 尝试不同的通知发现它确实在关闭时收到推送通知,当且仅当通知包含属性“message”时 ,如果没有,它只是丢弃它。 (Push notifications are just JSON objects). (推送通知只是JSON对象)。

My notifications contain all kind of attributes including "alert", "id" and "title", but only "message" makes Android to wake up the app. 我的通知包含所有类型的属性,包括“alert”,“id”和“title”,但只有“message”才能让Android唤醒应用。

Example notification that doesn't work : 示例通知不起作用

{ event: 'message',
  from: '947957531940',
  collapse_key: 'do_not_collapse',
  foreground: true,
  payload: 
   { alert: 'Mensaje de Prueba',
     title: 'Titulo Mensaje de Prueba' } }

Example notification that works : 例如通知的工作原理

{ 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.' } }

Is this an Android standard by design or am I doing something wrong in my app? 这是Android标准设计还是我在我的应用程序中做错了什么?

My app was developed using Ionic with Cordova. 我的应用程序是使用Ionic与Cordova开发的。

PD: Excuse my english. PD:请原谅我的英语。

EDIT: 编辑:

This is the Android push code inside the .run module in app.js, as ng-cordova instructions specify: 这是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){

  }
}

After searching all questions in stackoverflow involving Cordova/Phonegap Push Plugin I found de source of the problem. 在涉及Cordova / Phonegap推送插件的stackoverflow中搜索所有问题后,我找到了问题的来源。 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. 它在GCMIntentService.java文件中指定。

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". 这样,如果插件收到带有“alert”字段而不是“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. 现在,通知栏中的通知将首先显示字段“alert”而不是“title”,其次是预定义消息,而不是我的推送通知中不存在的字段“message”。

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. 因为这个原因,我失去了两天的实习机会,我花了很多时间写这篇文章,以便其他人不必这样做。

You are right @David prieto. 你是对的@David prieto。 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. 问题是插件源代码要求推送通知具有“消息”字段,以便在后台触发通知。

There is one way to put "message" field in push notification and its simple. 有一种方法可以将“消息”字段放在推送通知中并且简单。 Payload array which has data of notification, which is send through an API. 具有通知数据的有效载荷数组,通过API发送。 It should have an "message" field in it. 它应该有一个“消息”字段。 So the push notification will automatically have a message field in it and it will get detected in background as well as foreground. 因此推送通知将自动在其中包含一个消息字段,它将在后台和前台检测到。

I have the same problem and I solved by changing some lines of codes. 我有同样的问题,我通过更改一些代码行解决了。 I used phonegap-plugin-push plugin and changed this file.(for android platform only) 我使用了phonegap-plugin-push插件并更改了这个文件。(仅适用于android平台)

plugin folder : phonegap-plugin-push/src/android/com/adobe/phonegap/push/FCMService.java 插件文件夹phonegap-plugin-push / src / android / com / adobe / phonegap / push / FCMService.java

platform folder : android/src/com/adobe/phonegap/push/FCMService.java 平台文件夹android / src / com / adobe / phonegap / push / FCMService.java

You need to change one of two files, which depends on you already added platform or not. 您需要更改两个文件中的一个,这取决于您是否已添加平台。

  // 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. 这里,PushPlugin.sendExtras(),这是localNotification的触发器,showNotificationIfPossible()是电话通知的触发器。

So I changed the code like this. 所以我改变了这样的代码。

  // 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

So I can get the notification and process it using localNotification plugin as I want. 所以我可以根据需要获取通知并使用localNotification插件处理它。 Hope this will help you. 希望这会帮助你。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 离子推送通知无法打开应用,并且是单行 - Ionic push notification doesn't open app and is single line 当应用程序在后台时,Cordova推送通知不起作用 - Cordova push notification not working when app is in background 不使用推送通知的Cordova应用程序:“缺少推送通知权利” - Cordova app that doesn't use push notifications: “Missing push notification entitlement” Cordova-应用程序在后台模式下时推送通知行为 - Cordova - Push notification behavior while app is on background mode Capacitor/Ionic:在后台或应用程序被终止时处理推送通知 - Capacitor/Ionic: Handling push notification in background or when app was killed android 离子推送通知不打开后台应用程序 - Ionic push notification does not open the background app on android 如何制作离子推送通知甚至在后台触发应用程序? - How to make ionic push notification triggers the app even in background? 离子推送通知(背景信息) - Ionic Push notification(Background fone) Android 推送通知无法打开应用 - Android push notification doesn't open app 启动器活动改变了这就是为什么FCM推送通知在后台应用程序时不起作用的原因 - Launcher Activity changed that's why FCM Push Notification doesn't work while app in background
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM