Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notifications to Android 8.0+ are blocked because notification channels are required #341

Open
TheRealNate opened this issue Jul 13, 2018 · 118 comments

Comments

@TheRealNate
Copy link

No description provided.

@TheRealNate
Copy link
Author

TheRealNate commented Jul 13, 2018

According to https://developer.android.com/training/notify-user/channels

To register a notification channel, this code is executed:

private void createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is new and not in the support library
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        CharSequence name = getString(R.string.channel_name);
        String description = getString(R.string.channel_description);
        int importance = NotificationManager.IMPORTANCE_DEFAULT;
        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
        channel.setDescription(description);
        // Register the channel with the system; you can't change the importance
        // or other notification behaviors after this
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(channel);
    }
}

It's java that needs to be directly integrated into Cordova, or there needs to be a Cordova package allowing us to execute this from the JavaScript.

Note that the guide says:

Creating an existing notification channel with its original values performs no operation, so it's safe to call this code when starting an app.

@batcode007
Copy link

This might be of help :

PushNotification.createChannel(
  () => {
    console.log('success');
  },
  () => {
    console.log('error');
  },
  {
    id: 'testchannel1',
    description: 'My first test channel',
    importance: 3,
    vibration: true
  }
);

https://github.com/phonegap/phonegap-plugin-push/blob/master/docs/API.md#pushnotificationcreatechannel

@batcode007
Copy link

Any updates? Did you get it resolved?

@TheRealNate
Copy link
Author

Haven't gotten a chance to attempt implementing this fix yet, though it seems promising. Will update once I've tried it.

@TheRealNate
Copy link
Author

Follow up question. Once the channel is implemented, how do you specify the channel when sending the notification?

@TheRealNate TheRealNate changed the title Notifications to Android 8.0+ are logged in server but not shown on device Notifications to Android 8.0+ are blocked because notification channels are required Aug 10, 2018
@TheRealNate
Copy link
Author

Code works to register a channel. Now need to figure out how to send a notification to a specific channel.

@da314pc
Copy link
Collaborator

da314pc commented Aug 13, 2018

@TheRealNate
I think I've made progress, so in the payload you have to include the channel id:
"data": {
"title": "Hello Bob!",
"message": "Phonegap is awesome!",
"android_channel_id": "testchannel2"
}

we have to change:

Allow user to set payload:

var data = (notification.payload) ? { ejson: EJSON.stringify(notification.payload) } : {};

data.title = notification.title;
data.message = notification.text;

add something like:

data.android_channel_id = notification.channel_id

https://github.com/raix/push/blob/464d82469ca15b8579b469b7156a6c9d16874d9b/lib/server/push.api.js#L307-L310

@TheRealNate
Copy link
Author

I've made a fork for this repo with @da314pc's changes. I'll try testing it asap.

@TheRealNate
Copy link
Author

Would this be correct usage?

Push.send({ from: 'push', title: 'Hello World!', text: 'Lorem ipsum', android_channel_id: 'testchannel1', query: {} });

@da314pc
Copy link
Collaborator

da314pc commented Aug 13, 2018

@TheRealNate
I think you can use android_channel_id or whatever variable you want to call it,
as long as set in push.api.js
"data.android_channel_id = notification.android_channel_id"

I'll try testing it when I get home.

@TheRealNate
Copy link
Author

It seems to be removing the argument android_channel_id before it gets to the code around line 309

@da314pc
Copy link
Collaborator

da314pc commented Aug 13, 2018

@TheRealNate
Copy link
Author

TheRealNate commented Aug 13, 2018

Done, https://github.com/TheRealNate/push/blob/master/lib/common/notifications.js

Testing these changes. Is it enough to allow the argument?

@TheRealNate
Copy link
Author

I'm no longer getting the error message, so the channel id seems to be making it to the code in push/lib/server/push.api.js, yet notifications still don't seem to be working.

@da314pc
Copy link
Collaborator

da314pc commented Aug 13, 2018

@TheRealNate
Is the device token still registered in the database? In the debug settings does it say if it's been sent to any android devices.

If you registered the device:
We may have to check the "node-gcm" library. I have been doing some digging, but I'll keep checking to make sure the payload has the android channel Id available or it gets lost before it reaches the device.

in the readme:
data: {
key1: 'message1',
key2: 'message2'
},
notification: {
title: "Hello, World",
icon: "ic_launcher",
body: "This is a notification that will be displayed if your app is in the background."
}

but in:

https://github.com/TheRealNate/push/blob/41c7a8d8b535d9999475dded2d04a3c81da1970e/lib/server/push.api.js#L345-L352

It looks like we are adding formatting it slight differently.

@TheRealNate
Copy link
Author

The logs do confirm when Push.debug=true that it's reaching:

Push: Sent message "Hello World!" to 0 ios apps 8 android apps

And

ANDROID: Result of sender: {"multicast_id":xxx,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"xxx"}]}

@TheRealNate
Copy link
Author

TheRealNate commented Aug 13, 2018

As for node-gcm, you seem to be right. I cannot find any mention of notification channels anywhere in the GitHub repo (https://github.com/ToothlessGear/node-gcm/search?q=channel&unscoped_q=channel)

Perhaps the official API (https://firebase.google.com/docs/reference/admin/) could work?

@TheRealNate
Copy link
Author

TheRealNate commented Aug 13, 2018

Here's another weird thing. I am unable to send notifications directly from the Firebase Console. Maybe some changes to the manifest need to be made (https://firebase.google.com/docs/cloud-messaging/android/client)

@da314pc
Copy link
Collaborator

da314pc commented Aug 13, 2018

Yea I noticed that too. Even when the notifications were working they were never integrated into firebase. It always showed blank.

@da314pc
Copy link
Collaborator

da314pc commented Aug 13, 2018

So this is the correct format which is similar:
https://github.com/phonegap/phonegap-plugin-push/blob/master/docs/PAYLOAD.md#notification-vs-data-payloads

My recommended format for your push payload when using this plugin (while it differs from Google's docs) works 100% of the time:

{
"data": {
"title": "Test Notification",
"body": "This offer expires at 11:30 or whatever",
"notId": 10,
"surveyID": "ewtawgreg-gragrag-rgarhthgbad"
}
}

In the FCM-NODE:

Warning: on February 2, 2017, the Firebase Team released the admin.messaging() service to their node.js admin module. This new service makes this module kind of deprecated

@TheRealNate
Copy link
Author

TheRealNate commented Aug 13, 2018

@da314pc do you have any idea where they are obtaining surveyID? Also, how would you do this using Push.send? Would everything in data go inside payload?

@da314pc
Copy link
Collaborator

da314pc commented Aug 13, 2018

not sure

@da314pc
Copy link
Collaborator

da314pc commented Aug 13, 2018

@TheRealNate
one more thing to check,

in your Push.send: did you remember to include the android_channel_id?

@TheRealNate
Copy link
Author

TheRealNate commented Aug 13, 2018 via email

@da314pc
Copy link
Collaborator

da314pc commented Aug 13, 2018

So everything looks fine, but when you send the notification from the server:

Push.send({
from: 'test',
title: 'test',
text: "Hello, World"',
query: {
userId: "user1"
}, //
android_channel_id: "testchannel1" //channel you put in the client
});

@TheRealNate
Copy link
Author

TheRealNate commented Aug 13, 2018 via email

@da314pc
Copy link
Collaborator

da314pc commented Aug 13, 2018

That's probably the problem, the device token is registered with the userId, so if the userId is blank, the Push notification can't find the device token in the database,

Push looks up the collection by userId ("im pretty sure")

Its all database driven, so for the test, make sure in the
"db._raix_push_app_tokens", there is a token with the userId,

then send the userId in query from the server,

so you kind of have to have a user logged in for this to work.

@TheRealNate
Copy link
Author

TheRealNate commented Aug 13, 2018 via email

@lokiribeiro
Copy link

Will this be implemented in the official release version?

@Edgy1337
Copy link

After adding all the dependencies and loading the plugin, my app still won't connect to google firebase.

@da314pc
Copy link
Collaborator

da314pc commented Nov 21, 2018

@CineXMike what issue are you getting? Also are you using the repo I have?

@Edgy1337
Copy link

No issue,
IOS working fine,
Just android isnt connecting to google firebase.
I included your things in build.gradle aswell
On the android phone the notification chanel is being created tho.

@da314pc
Copy link
Collaborator

da314pc commented Dec 14, 2018

@CineXMike your sending the channel on the server too?

@aboire
Copy link
Collaborator

aboire commented Dec 15, 2018

@da314pc I test this fork https://github.com/FishSaidNo/push la to switch to FCM on meteor 1.8
https://github.com/FishSaidNo/push/blob/master/docs/FCM.md (android target 26)
be up to date at android studio (tool, sdk, ...)

for build you have to use that for me
meteor/meteor#7600 (comment)
put the build-extras.gradle file at the root of the project meteor /cordova-build-override/platforms/android/build-extras.gradle

buildscript {
    repositories {
        jcenter()
        mavenLocal()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:+'
        classpath 'com.google.gms:google-services:3.0.0'
    }
}

ext.postBuildExtras = {
    apply plugin: com.google.gms.googleservices.GoogleServicesPlugin

    def inAssetsDir = file("assets")
    def outAssetsDir = inAssetsDir
    def outFile = new File(outAssetsDir, "cdvasset.manifest")

    def newTask = task("cdvCreateAssetManifest") << {
        def contents = new HashMap()
        def sizes = new HashMap()
        contents[""] = inAssetsDir.list()
        def tree = fileTree(dir: inAssetsDir)
        tree.visit { fileDetails ->
            if (fileDetails.isDirectory()) {
                contents[fileDetails.relativePath.toString()] = fileDetails.file.list()
            } else {
                sizes[fileDetails.relativePath.toString()] = fileDetails.file.length()
            }
        }

        outAssetsDir.mkdirs()
        outFile.withObjectOutputStream { oos ->
            oos.writeObject(contents)
            oos.writeObject(sizes)
        }
    }
    newTask.inputs.dir inAssetsDir
    newTask.outputs.file outFile
    def preBuildTask = tasks["preBuild"]
    preBuildTask.dependsOn(newTask)
}

in /mobile-config.js add in addition to the rest

App.configurePlugin ('phonegap-plugin-push', {
   SENDER_ID: xxxxxxxxxx
});

App.addResourceFile ('google-services.json', 'google-services.json', 'android');

add google-services.json to the root of your meteor project

be careful if you went from "raix:push" to this fork the client side configuration there is "cordovaOptions" which includes the config which was not present before

do not forget that "payload" must be JSON.stringify with FCM

you need to activate the FCM API https://console.developers.google.com/apis/api/fcm.googleapis.com/overview?project=XXXXXXXXXX

if you want to configure FCM for ios https://medium.com/@felipepucinelli/how-to-add-push-notifications-in-your-cordova-application-using-firebase-69fac067e821
and add GoogleService-Info.plist to the root of your project meteor and add these lines to your mobile-config.js, APP_NAME should be replaced with the real app name

App.addResourceFile ('GoogleService-Info.plist', 'APP_NAME/Resources/GoogleService-Info.plist', 'ios');

Doc
https://github.com/raix/push/blob/master/docs/ANDROID.md
https://github.com/FishSaidNo/push/blob/master/docs/FCM.md
Migrate a GCM Client App for Android to Firebase Cloud Messaging
https://developers.google.com/cloud-messaging/android/android-migrate-fcm
meteor/meteor#9748

@MrSpark2591
Copy link

MrSpark2591 commented Dec 19, 2018

Migrate a GCM Client App for Android to Firebase Cloud Messaging

By any chance this fork can be merged to original repo and we can have new major release on this. @raix
and other things like and adding file and all gets documented in official docs. @aboire

@da314pc
Copy link
Collaborator

da314pc commented Dec 21, 2018

@MrSpark2591 this project needs a new maintainer. Once we get that settled we can add in the changes and update the docs to make it easy for anyone to upgrade for android 8

@MrSpark2591
Copy link

@da314pc Let me know if i can be helpful. I will be more than happy to contribute :)

@da314pc
Copy link
Collaborator

da314pc commented Dec 21, 2018

@MrSpark2591 #356

@lokiribeiro
Copy link

Hi @da314pc ,

Is your version already implemented with the official release? Your version works on local servers but we cant seem to implement it in the production server since it is installing raix:push.

Thanks

@ashish979
Copy link

Hi @da314pc

Can you provide the exact step to make notification working on Android 8+?

I tried with your fork of the repo. No error is coming but there are no notifications as well.
Overriding build.gradle causes build to fail due to dependency conflict as I am using other google services as well.

Thanks

@da314pc
Copy link
Collaborator

da314pc commented Jan 22, 2019

@ashish979 I will integrate the code into the and update the repo. What errors are you seeing in your gradle file?

@ashish979
Copy link

@da314pc I test this fork https://github.com/FishSaidNo/push la to switch to FCM on meteor 1.8
https://github.com/FishSaidNo/push/blob/master/docs/FCM.md (android target 26)
be up to date at android studio (tool, sdk, ...)

for build you have to use that for me
meteor/meteor#7600 (comment)
put the build-extras.gradle file at the root of the project meteor /cordova-build-override/platforms/android/build-extras.gradle

buildscript {
    repositories {
        jcenter()
        mavenLocal()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:+'
        classpath 'com.google.gms:google-services:3.0.0'
    }
}

ext.postBuildExtras = {
    apply plugin: com.google.gms.googleservices.GoogleServicesPlugin

    def inAssetsDir = file("assets")
    def outAssetsDir = inAssetsDir
    def outFile = new File(outAssetsDir, "cdvasset.manifest")

    def newTask = task("cdvCreateAssetManifest") << {
        def contents = new HashMap()
        def sizes = new HashMap()
        contents[""] = inAssetsDir.list()
        def tree = fileTree(dir: inAssetsDir)
        tree.visit { fileDetails ->
            if (fileDetails.isDirectory()) {
                contents[fileDetails.relativePath.toString()] = fileDetails.file.list()
            } else {
                sizes[fileDetails.relativePath.toString()] = fileDetails.file.length()
            }
        }

        outAssetsDir.mkdirs()
        outFile.withObjectOutputStream { oos ->
            oos.writeObject(contents)
            oos.writeObject(sizes)
        }
    }
    newTask.inputs.dir inAssetsDir
    newTask.outputs.file outFile
    def preBuildTask = tasks["preBuild"]
    preBuildTask.dependsOn(newTask)
}

in /mobile-config.js add in addition to the rest

App.configurePlugin ('phonegap-plugin-push', {
   SENDER_ID: xxxxxxxxxx
});

App.addResourceFile ('google-services.json', 'google-services.json', 'android');

add google-services.json to the root of your meteor project

be careful if you went from "raix:push" to this fork the client side configuration there is "cordovaOptions" which includes the config which was not present before

do not forget that "payload" must be JSON.stringify with FCM

you need to activate the FCM API https://console.developers.google.com/apis/api/fcm.googleapis.com/overview?project=XXXXXXXXXX

if you want to configure FCM for ios https://medium.com/@felipepucinelli/how-to-add-push-notifications-in-your-cordova-application-using-firebase-69fac067e821
and add GoogleService-Info.plist to the root of your project meteor and add these lines to your mobile-config.js, APP_NAME should be replaced with the real app name

App.addResourceFile ('GoogleService-Info.plist', 'APP_NAME/Resources/GoogleService-Info.plist', 'ios');

Doc
https://github.com/raix/push/blob/master/docs/ANDROID.md
https://github.com/FishSaidNo/push/blob/master/docs/FCM.md
Migrate a GCM Client App for Android to Firebase Cloud Messaging
https://developers.google.com/cloud-messaging/android/android-migrate-fcm
meteor/meteor#9748

Finally I got this working with https://github.com/FishSaidNo/push fork.
@aboire Thanks for the elaborated explanation.

For future reference, below is the series of steps I followed:

  1. Use https://github.com/FishSaidNo/push fork.
  2. Make sure to add the necessary versions of cordova plugins and npm packages in your repo.
  3. client config
if (Meteor.isDevelopment) {
  Push.debug = true;
}

Meteor.startup(function () {
  if (Meteor.isCordova) {
    PushNotification.createChannel(
      function () {
        console.log('Channel Created!');
      },
      function () {
        console.log('Channel not created :(');
      }, {
        id: 'PushPluginChannel',
        description: 'Channel Name Shown To Users',
        importance: 3,
        vibration: true,
      },
    );

    Push.Configure({
      cordovaOptions: {
        // Options here are passed to phonegap-plugin-push
        android: {
          sound: true,
          vibrate: true,
          clearBadge: false,
          clearNotifications: true,
          forceShow: false,
          // icon: 'ic_stat_co_24',
          // iconColor: '#6B97AF',
        },
      },
      appName: 'main'
    });

    Push.addListener('startup', function () {
      Router.go('/notifications');
    });

    Push.addListener('message', function (notification) {
      function alertDismissed(buttonIndex) {
        if (buttonIndex === 1) {
          const payload = JSON.parse(notification.payload.custom_key1);
          if (payload.url) {
            Router.go('/notifications');
          } else {
            Router.go('/notifications');
          }
        }
      }
      window.confirm(notification.message, alertDismissed, 'notifications', ['Voir', 'fermer']);
    });
  }
});
  1. server config
const serviceAccountJson = JSON.parse(Assets.getText('FirebaseAdminSdkServiceAccountKey.json'));

/*
what to do to get the FirebaseAdminSdkServiceAccountKey.json credential file to copy to the /private directory of your meteor project

https://firebase.google.com/docs/admin/setup
To use the Firebase Admin SDKs, you'll need a Firebase project, a service account to communicate with the Firebase service, and a configuration file with your service account's credentials.
If you don't already have a Firebase project, add one in the Firebase console. The Add project dialog also gives you the option to add Firebase to an existing Google Cloud Platform project.
Navigate to the Service Accounts tab in your project's settings page.
Click the Generate New Private Key button at the bottom of the Firebase Admin SDK section of the Service Accounts tab.
After you click the button, a JSON file containing your service account's credentials will be downloaded. You'll need this to initialize the SDK in the next step.

you need to activate the FCM API https://console.developers.google.com/apis/api/fcm.googleapis.com/overview?project=id of your project
*/

if (Meteor.isDevelopment) {
  Push.debug = true;
}

Push.Configure({
    fcm: {
      serviceAccountJson: serviceAccountJson
    },
    production: true,
    sound: true,
    badge: true,
    alert: true,
    vibrate: true,
    appName: 'main',
  });

Push.allow({
  send(userId, notification) {
    return true;
  },
});
  1. Test push
const notId = Math.round(new Date().getTime() / 1000);

const title = 'new notification';
const text = 'you have a new notification';
//custom info
const payload = {info:'test', url:'http://www.google.fr'};
//number
const badge = 5;

  const payloadStringify = {};
  payloadStringify.custom_key1 = JSON.stringify(payload);

  Push.send({
    from: 'push',
    title,
    text,
    payload: payloadStringify, // All payload values must be strings if sending using FCM
    sound: 'default',
    query,
    badge,
    apn: {
      sound: 'default',
    },
    contentAvailable: 1,
    androidChannel: 'PushPluginChannel',
    notId,
  });
};

  1. Add the below file cordova-build-override/platforms/android/build-extras.gradle
buildscript {
    repositories {
        jcenter()
        maven {
            url 'https://maven.google.com'
        }
    }

    dependencies {
            classpath 'com.android.tools.build:gradle:3.2.1'
            classpath 'com.google.gms:google-services:4.1.0'
            classpath 'com.google.firebase:firebase-core:16.0.6'
        }
}

ext.postBuildExtras = {
    apply plugin: com.google.gms.googleservices.GoogleServicesPlugin

    def inAssetsDir = file("assets")
        def outAssetsDir = inAssetsDir
        def outFile = new File(outAssetsDir, "cdvasset.manifest")

        def newTask = task("cdvCreateAssetManifest") << {
            def contents = new HashMap()
            def sizes = new HashMap()
            contents[""] = inAssetsDir.list()
            def tree = fileTree(dir: inAssetsDir)
            tree.visit { fileDetails ->
                if (fileDetails.isDirectory()) {
                    contents[fileDetails.relativePath.toString()] = fileDetails.file.list()
                } else {
                    sizes[fileDetails.relativePath.toString()] = fileDetails.file.length()
                }
            }

            outAssetsDir.mkdirs()
            outFile.withObjectOutputStream { oos ->
                oos.writeObject(contents)
                oos.writeObject(sizes)
            }
        }
        newTask.inputs.dir inAssetsDir
        newTask.outputs.file outFile
        def preBuildTask = tasks["preBuild"]
        preBuildTask.dependsOn(newTask)
}

Try to build it with all these configurations. Notifications in android should work.

@aboire
Copy link
Collaborator

aboire commented Jan 24, 2019

@ashish979 with version [email protected] (version of cordova update) more need to use build-extras.gradle and one can use version [email protected]

@ashish979
Copy link

@ashish979 with version [email protected] (version of cordova update) more need to use build-extras.gradle and one can use version [email protected]

@aboire I tried building with 1.8.1-beta.15 but breaking the ios build also. So, for the time being I will go with the above configuration and wait for a stable release of 1.8.

@da314pc Thanks for the help but with your configuration, I am not able to build the app. Therefore, as I said I am going with the above configuration.

#359 #354 Both pull requests have similar changes. @raix Can you review and merge any any one of them so that this issue is closed.

@aboire
Copy link
Collaborator

aboire commented Jan 24, 2019

@ashish979 what is the error on ios, me I build without problem?
for my part I selected SWIFT_VERSION version 3.2 for it to pass
and do "pod install" in the project (1.8.1-beta.15 and [email protected])
and in mobile-config I have:
App.addResourceFile ('google-services.json', 'app/google-services.json', 'android');
App.addResourceFile ('GoogleService-Info.plist', 'GoogleService-Info.plist', 'ios');

@da314pc
Copy link
Collaborator

da314pc commented Jan 24, 2019

@ashish979 were in the processes of getting the pull request merged in,
I think your facing issues regarding similar google libraries clashing in your gradle file. You have to force the version

#359
If you look at my pull request docs:

configurations.all {
resolutionStrategy {
force 'com.android.support:support-v4:27.1.0'
}
}
configurations {
all*.exclude group: 'com.android.support', module: 'support-v13'
}


your going to have add a similar command. Soon as we get the request merged in I can try to help walk you through it.

@ashish979
Copy link

@aboire @da314pc Thank you so much for all the help. Currently I am able to get the notifications working. Now, I will wait for 1.8.1 release and a new version of this package.

Also, We are using meteor and this package heavily. @raix we will be happy to contribute as well.

@raix
Copy link
Collaborator

raix commented Jan 26, 2019

@ashish979 let me know if I should add you on the contributor team

@ashish979
Copy link

Yes, you can.

@da314pc
Copy link
Collaborator

da314pc commented Feb 5, 2019

@ashish979 @lokiribeiro we have just merged in the changes into the release.

@namenotrequired
Copy link

namenotrequired commented Apr 5, 2019

Thanks so much to the contributors and others that researched this and updated the package and the readme to make it work!

I've been struggling to get it to work in my own app, likely due to dependency issues. But I made a small dummy app in which it's working perfectly in Android both 7 and 8.

I thought I'd share it here in case it helps anyone: https://github.com/namenotrequired/meteor-push-example

@eicksl
Copy link

eicksl commented May 24, 2019

Is the FishSaidNo fork the only option for FCM with Meteor 1.8?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests