Cordova local notification doesn't work while

2020-03-29 19:38发布

问题:

I'm developing an android application using Cordova and it uses PushPlugin to receive push notifications from my server.

In particular, I'm doing some test using the PushPlugin Example.

I'm also using the Cordova Local Notification plugin because I want the app shows a local notification as soon as it receives a push notification.

The following code works and the local notification appears but only when the app is in the foreground.

I want the local notification appear even when the app is in the background. Is it possible? How can I make it work?

thanks in advance

<!DOCTYPE HTML>
<html>
    <head>
        <title>com.PhoneGap.c2dm</title>
    </head>
    <body>

    <script type="text/javascript" charset="utf-8" src="cordova.js"></script>
    <script type="text/javascript" charset="utf-8" src="jquery_1.5.2.min.js"></script>
    <script type="text/javascript" src="PushNotification.js"></script>

    <script type="text/javascript">
        var pushNotification;

        function onDeviceReady() {
            $("#app-status-ul").append('<li>deviceready event received</li>');

                    document.addEventListener("backbutton", function(e){
                $("#app-status-ul").append('<li>backbutton event received</li>');

                    if( $("#home").length > 0){
                            // call this to get a new token each time. don't call it to reuse existing token.
                            //pushNotification.unregister(successHandler, errorHandler);
                            e.preventDefault();
                            navigator.app.exitApp();
                        }
                        else{
                            navigator.app.backHistory();
                        }
                    }, false);
                    try{ 
                    pushNotification = window.plugins.pushNotification;
                        $("#app-status-ul").append('<li>registering ' + device.platform + '</li>');
                        if (device.platform == 'android' || device.platform == 'Android' || device.platform == 'amazon-fireos' ){
                                 pushNotification.register(successHandler, errorHandler, {"senderID":"527085141383","ecb":"onNotification"});   
                                  } else {
                             pushNotification.register(tokenHandler, errorHandler, {"badge":"true","sound":"true","alert":"true","ecb":"onNotificationAPN"});   // obbligatorio!
                        }
                    }
                    catch(err) { 
                        txt="There was an error on this page.\n\n"; 
                        txt+="Error description: " + err.message + "\n\n"; 
                        alert(txt); 
                    } 
        }   // fine onDeviceReady


        function onNotificationAPN(e) {
            if (e.alert) {
                 $("#app-status-ul").append('<li>push-notification: ' + e.alert + '</li>');
                 // showing an alert also requires the org.apache.cordova.dialogs plugin
                 navigator.notification.alert(e.alert);
            }

            if (e.sound) {
                // playing a sound also requires the org.apache.cordova.media plugin
                var snd = new Media(e.sound);
                snd.play();
            }

            if (e.badge) {
                pushNotification.setApplicationIconBadgeNumber(successHandler, e.badge);
            }
        }

        function onNotification(e) {
            $("#app-status-ul").append('<li>EVENT -> RECEIVED:' + e.event + '</li>');

            switch( e.event ){
                case 'registered':
                            if ( e.regid.length > 0 )
                            {
                                $("#app-status-ul").append('<li>REGISTERED -> REGID:' + e.regid + "</li>");
                                // Your GCM push server needs to know the regID before it can push to this device
                                // here is where you might want to send it the regID for later use.
                                console.log("regID = " + e.regid);
                            }
                    break;

                case 'message':
                    // if this flag is set, this notification happened while we were in the foreground.
                    // you might want to play a sound to get the user's attention, throw up a dialog, etc.

                      var notificaOk = function(){
                        console.log("OK");
                      }
                      var notificaKo = function(){
                        console.log("KO");
                      }

                      window.plugin.notification.local.add({id: 1, title: "Product available", message: "Nexus 6 in stock", smallIcon: 'ic_dialog_email', icon: 'ic_launcher'}, notificaOk, notificaKo);

                    if (e.foreground){
                                   $("#app-status-ul").append('<li>--INLINE NOTIFICATION--' + '</li>');

                                  // on Android soundname is outside the payload. 
                                // On Amazon FireOS all custom attributes are contained within payload
                                var soundfile = e.soundname || e.payload.sound;
                                // if the notification contains a soundname, play it.
                                // playing a sound also requires the org.apache.cordova.media plugin
                                var my_media = new Media("/android_asset/www/"+ soundfile);

                                     my_media.play();

                              }
                              else{ // otherwise we were launched because the user touched a notification in the notification tray.

                                if (e.coldstart)
                                     $("#app-status-ul").append('<li>--COLDSTART NOTIFICATION--' + '</li>');
                                else
                                   $("#app-status-ul").append('<li>--BACKGROUND NOTIFICATION--' + '</li>');
                            }

                            $("#app-status-ul").append('<li>MESSAGE -> MSG: ' + e.payload.message + '</li>');
                              //android only
                            $("#app-status-ul").append('<li>MESSAGE -> MSGCNT: ' + e.payload.msgcnt + '</li>');
                              //amazon-fireos only
                              $("#app-status-ul").append('<li>MESSAGE -> TIMESTAMP: ' + e.payload.timeStamp + '</li>');

                      break;

                case 'error':
                            $("#app-status-ul").append('<li>ERROR -> MSG:' + e.msg + '</li>');
                          break;

                          default:
                            $("#app-status-ul").append('<li>EVENT -> Unknown, an event was received and we do not know what it is</li>');
                          break;
                  }
        }

        function tokenHandler (result) {
            $("#app-status-ul").append('<li>token: '+ result +'</li>');
            // Your iOS push server needs to know the token before it can push to this device
            // here is where you might want to send it the token for later use.
        }

        function successHandler (result) {
            $("#app-status-ul").append('<li>success:'+ result +'</li>');
        }

        function errorHandler (error) {
            $("#app-status-ul").append('<li>error:'+ error +'</li>');
        }

             document.addEventListener('deviceready', onDeviceReady, true);

     </script>
    <div id="home">
        <div id="app-status-div">
            <ul id="app-status-ul">
                <li>Cordova PushNotification Plugin Demo</li>
            </ul>
        </div>
    </div>
</body>
</html>

then I send a push notification to my device with the following nodeJS script:

var GCM = require('gcm').GCM;

var apiKey = "***";

var gcm = new GCM(apiKey);

var devRegIdTarget = "APA9....";

var message = {
    message: "Text msg",
    registration_id : devRegIdTarget, 
    title : 'Title',
    msgcnt : '1',
    collapseKey : "msg1",
    soundname : 'beep.wav'
};

message.timeToLive = 3000;
message.delayWhileIdle = true;

gcm.send(message, function(err, messageId){
    if (err) {
        console.log("Something has gone wrong!");
    } else {
        console.log("Sent with message ID: ", messageId);
    }
});

回答1:

I had similar experience in using PushPlugin and LocalNotification.

For my case, notification worked on the background but smallicon for the android were white blank.

I spent whole night inspecting source of LocalNotification plugin but it turned out it was problem with PushPlugin itself. (I will say, the exact problem is disconnection between two plugins) In the source code of PushPlugin, It checks whether application is in foreground or background.

If application is in the background, notification event is not triggered to the cordova app but PushPlugin creates itself it's own local notification.

    @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) {
                createNotification(context, extras);
            }
        }
    }
}

So, if you want to use customised smallicon when application is running in the back.

I did a quick hack by overriding initial code to

    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(getResourceId(context, "pushicon", "drawable", context.getPackageName()))
                .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), getResourceId(context, "icon", "drawable", context.getPackageName())))
                .setWhen(System.currentTimeMillis())
                .setContentTitle(extras.getString("title"))
                .setTicker(extras.getString("title"))
                .setContentIntent(contentIntent)
                .setAutoCancel(true);

    String message = extras.getString("message");
    if (message != null) {
        mBuilder.setContentText(message);
    } else {
        mBuilder.setContentText("<missing message content>");
    }

    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, all you need to do is put image named "pushicon" in drawable folder platforms/android/res/drawable/pushicon.png (I made it use image "icon" for large icon as well)

if it's to much of hassle, I made a git repo for this https://github.com/zxshinxz/PushPlugin.git

cordova plugin add https://github.com/zxshinxz/PushPlugin.git

hope other programmer don't go through the pain I went through.



回答2:

i think you also need to add another plugin too, for running application in background mode,

please refer to the below link, https://github.com/Red-Folder/Cordova-Plugin-BackgroundService

another link, How to run cordova plugin in Android background service?