I have implemented firebase cloud messaging in my Android app. When I send notification from backed or Firebase console onMessageReceived() is triggered twice and generates two notifications on device. I've tried to search on internet but no results found for this problem
here is my code,
MyFirebaseNotificationService.java
public class MyFirebaseNotificationService extends FirebaseMessagingService {
#Override
public void onNewToken(String s) {
super.onNewToken(s);
MyApp.getInstance().saveFCMToken(s);
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
int notificationId = new Random().nextInt(60000);
String customerId = "";
Log.e("NOTIF", "" + remoteMessage.getData());
Intent notificationIntent = new Intent(this, SplashActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
notificationIntent.setAction(Long.toString(System.currentTimeMillis()));
final PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, "100")
.setSmallIcon(R.drawable.ic_app_icon)
.setColorized(true)
.setPriority(PRIORITY_HIGH)
.setColor(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))
.setContentTitle(Html.fromHtml(remoteMessage.getData().get("title")))
.setContentText(Html.fromHtml(remoteMessage.getData().get("message")))
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_SOUND)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
createNotificationChannel();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(notificationId, notificationBuilder.build());
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Exchange Customer";
String description = "Sales Buddy";
String CHANNEL_ID = "100";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
getSystemService(NotificationManager.class).createNotificationChannel(channel);
}
}
}
AndroidManifest
<service android:name=".sevices.MyFirebaseNotificationService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Permissions in Manifest
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
On Message received I've logged notification and here is logcat
2019-05-01 15:08:54.415 29417-29501/in.example.one E/NOTIF: {extras={"customerId":"5e341186-6bd4-11e9-9069-44a8422a303b"}, type=exchange, title=Test User:1556703533, message=Test User1}
2019-05-01 15:08:58.542 29417-29501/in.example.one E/NOTIF: {extras={"customerId":"5e341186-6bd4-11e9-9069-44a8422a303b"}, type=exchange, title=Test User:1556703533, message=Test User1}
here you can see same notification log is printing twice and both notifications are displaying on device
Project Gradle File
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0'
classpath 'com.google.gms:google-services:4.2.0'
classpath 'io.fabric.tools:gradle:1.26.1'
}
Module Gradle File
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.squareup.picasso:picasso:2.5.2'
implementation 'com.amitshekhar.android:android-networking:1.0.2'
implementation 'com.github.WindSekirun:SectionCalendarView:1.0.5.1'
implementation 'com.github.darsh2:MultipleImageSelect:v0.0.4'
implementation 'com.bogdwellers:pinchtozoom:0.1'
implementation 'com.google.firebase:firebase-core:16.0.8'
implementation 'com.google.firebase:firebase-messaging:17.6.0'
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9'
implementation 'com.google.firebase:firebase-database:16.1.0'
}
My Php code
$extras= json_encode(['customerId' => "5e341186-6bd4-11e9-9069-44a8422a303b"]);
$data=array(
'title'=> "Test User:".time(),
'message'=> "Test User1",
'type'=> "exchange",
'extras'=>$extras
);
$notification=array(
'title'=> "Test User:".time(),
'body'=> "body1",
);
$fields = array
(
'to'=>'/topics/test-exchange-persons-sales-buddy',
'data' => $data
);
$headers = array
(
'Authorization: key=' . API_ACCESS_KEY,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt( $ch,CURLOPT_URL, 'https://fcm.googleapis.com/fcm/send' );
curl_setopt( $ch,CURLOPT_POST, true );
curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );
curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );
curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) );
$result = curl_exec($ch );
curl_close( $ch );
echo $result;
I have the same issue since yesterday (using topics too). As a workaround, until it gets fixed I'm doing this in my FirebaseMessagingService:
private static ArrayList<Long> alreadyNotifiedTimestamps = new ArrayList<>();
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (!isDuplicate(remoteMessage.getSentTime())) {
// send notificaiton here
}
}
// Workaround for Firebase duplicate pushes
private boolean isDuplicate(long timestamp) {
if (alreadyNotifiedTimestamps.contains(timestamp)) {
alreadyNotifiedTimestamps.remove(timestamp);
return true;
} else {
alreadyNotifiedTimestamps.add(timestamp);
}
return false;
}
I have tha same problem but with Firebase Messaging Topics. I recive two notification beacuase "onMessageReceived" called twice like you. Maybe a problem from FCM today?
I had also faced similar issue, Because of implementation 'com.google.firebase:firebase-messaging:17.6.0', So then i just used implementation 'com.google.firebase:firebase-messaging:17.3.3' version of messaging then everything worked correctly
Related
So working on this reminds me of why I absolutely hate remote push notifications. Xamarin Forms solution, specifically trying to get remote push notifications to work in an ad-hoc distributed .apk file.
Here's the relevant code:
FireBaseService in the Android Native project:
using Android.App;
using Android.Content;
using Android.Util;
using AndroidX.Core.App;
using Firebase.Messaging;
using Newtonsoft.Json;
using Mobile.Client.Configuration;
using System;
using System.Linq;
using WindowsAzure.Messaging;
using Xamarin.Forms;
namespace Mobile.Client.Droid.Notifications
{
[Service]
[IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
public class FirebaseService : FirebaseMessagingService
{
const string TAG = "FirebaseService";
public override void OnMessageReceived(RemoteMessage message)
{
Log.Debug(TAG, "From: " + message.From);
if (message.GetNotification() != null)
{
//These is how most messages will be received
Log.Debug(TAG, "Notification Message Body: " + message.GetNotification().Body);
SendNotification(message.GetNotification().Body);
}
else
{
//Only used for debugging payloads sent from the Azure portal
SendNotification(message.Data.Values.First());
}
}
public override async void OnNewToken(string token)
{
Log.Info(TAG, $"Registration Token: {token}");
App.Current.Properties["NotificationToken"] = token;
await App.Current.SavePropertiesAsync();
SendRegistrationToServer(token);
}
private void SendNotification(string messageBody)
{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.UpdateCurrent);
var notificationChannelName = AppSettingsManager.Settings["NotificationChannelName"];
var notificationBuilder = new NotificationCompat.Builder(this, notificationChannelName);
notificationBuilder.SetContentTitle("Notification")
.SetSmallIcon(Resource.Drawable.nndc_logo)
.SetContentText(messageBody)
.SetAutoCancel(true)
.SetAllowSystemGeneratedContextualActions(true)
.SetShowWhen(false)
.SetContentIntent(pendingIntent);
var notificationManager = NotificationManager.FromContext(this);
notificationManager.Notify(0, notificationBuilder.Build());
MessagingCenter.Send(App.Current, "NotificationRecieved");
}
private void SendRegistrationToServer(string token)
{
try
{
var notificationHubName = AppSettingsManager.Settings["NotificationHubName"];
var listenConnectionString = AppSettingsManager.Settings["ListenConnectionString"];
var subscriptionTags = AppSettingsManager.Settings["SubscriptionTags"]?.Split(",");
var fCMTemplateBody = AppSettingsManager.Settings["FCMTemplateBody"];
NotificationHub hub = new NotificationHub(notificationHubName, listenConnectionString, this);
Log.Info(TAG, $"Created hub object: {hub.NotificationHubPath}");
// register device with Azure Notification Hub using the token from FCM
Registration registration = hub.Register(token, subscriptionTags);
Log.Info(TAG, $"Registered token and tags: {registration.PNSHandle}");
// subscribe to the SubscriptionTags list with a simple template.
string pnsHandle = registration.PNSHandle;
Log.Info(TAG, $"PNS Handle: {pnsHandle}");
TemplateRegistration templateReg = hub.RegisterTemplate(pnsHandle, "defaultTemplate", fCMTemplateBody, subscriptionTags);
Log.Info(TAG, $"Registered template: {templateReg.NotificationHubPath}");
}
catch (Exception e)
{
Log.Info(TAG, $"PNS REGISTRATION EXCEPTION: {JsonConvert.SerializeObject(e)}");
//Log.Error("DEBUG", $"Error registering device: {e.Message}");
}
}
}
}
Android Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.android.mobile" android:installLocation="auto">
<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="28" />
<!--android:extractNativeLibs="true" had to be added below due to a VS/Xamarin Bug: https://github.com/xamarin/xamarin-android/issues/4990-->
<application android:label="APPNAME" android:icon="#mipmap/icon" android:extractNativeLibs="true" android:roundIcon="#mipmap/icon_round">
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdInternalReceiver" android:exported="false" />
<receiver android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="${applicationId}" />
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.BLUETOOTH" />
</manifest>
Anyway as the title says, this works fine in Debug, it registers with no issue and sends push notifications from azure absolutely fine. Now the FCM key is the same key for sandbox or production as far as I can tell, so I don't think it's that, but feel free to correct me if I'm wrong.
If I run this in release, or install it ad-hoc as an apk file installation I get the following error:
{
"JniPeerMembers": {
"ManagedPeerType": "WindowsAzure.Messaging.NotificationHubException, Xamarin.Azure.NotificationHubs.Android, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"JniPeerTypeName": "com/microsoft/windowsazure/messaging/NotificationHubException",
"JniPeerType": {
"PeerReference": {
"Handle": {
"value": 15194
},
"Type": 2,
"IsValid": true
},
"Name": "com/microsoft/windowsazure/messaging/NotificationHubException"
},
"InstanceMethods": {},
"InstanceFields": {},
"StaticMethods": {},
"StaticFields": {}
},
"StatusCode": 400,
"StackTrace": "
at Java.Interop.JniEnvironment+InstanceMethods.CallObjectMethod (Java.Interop.JniObjectReference instance,
Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <3f19c9fc57a34ac9a473579164f8755e>:0 \n
at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualObjectMethod (System.String encodedMember,
Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x0002a] in <3f19c9fc57a34ac9a473579164f8755e>:0 \n
at WindowsAzure.Messaging.NotificationHub.Register (System.String pnsHandle, System.String[] tags) [0x00043] in <15ee46979411457bb0abfed951cc2b1e>:0 \n
at NorthNorfolk.Mobile.Client.Droid.Notifications.FirebaseService.SendRegistrationToServer (System.String token) [0x00078] in <f0d16bc144b04854b79558630f62c467>:0 \n
--- End of managed WindowsAzure.Messaging.NotificationHubException stack trace
---\ncom.microsoft.windowsazure.messaging.NotificationHubException\n\tat
com.microsoft.windowsazure.messaging.Connection.executeRequest(Connection.java:254)\n\tat
com.microsoft.windowsazure.messaging.Connection.executeRequest(Connection.java:170)\n\tat
com.microsoft.windowsazure.messaging.Connection.executeRequest(Connection.java:130)\n\tat
com.microsoft.windowsazure.messaging.NotificationHub.upsertRegistrationInternal(NotificationHub.java:446)\n\tat
com.microsoft.windowsazure.messaging.NotificationHub.registerInternal(NotificationHub.java:410)\n\tat
com.microsoft.windowsazure.messaging.NotificationHub.register(NotificationHub.java:148)\n\tat
com.northnorfolk.mobile.FirebaseService.n_onNewToken(Native Method)\n\tat
com.northnorfolk.mobile.FirebaseService.onNewToken(FirebaseService.java:38)\n\tat
com.google.firebase.messaging.FirebaseMessagingService.zzd(Unknown Source:86)\n\tat
com.google.firebase.iid.zzg.run(Unknown Source:4)\n\tat
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)\n\tat
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)\n\tat
com.google.android.gms.common.util.concurrent.zza.run(Unknown Source:6)\n\tat
java.lang.Thread.run(Thread.java:919)\n",
"JniIdentityHashCode": 19017287,
"PeerReference": {
"Handle": {
"value": 19298
},
"Type": 2,
"IsValid": true
},
"Handle": {
"value": 19298
},
"Message": null,
"Data": {},
"InnerException": null,
"Source": "mscorlib",
"HResult": -2146233088
}
This is thrown from the FirebaseService class from this method:
// register device with Azure Notification Hub using the token from FCM
Registration registration = hub.Register(token, subscriptionTags);
---Update---
I've raised this against the repo on github too at this link. They suggested messaging around the proguard or r8. I actually didn't have these set but because I know Xamarin and VS sometimes do their own thing I setup the r8 shrinker and now when I run this I get the following error which looks a little more descriptive as it shows a 400 error potentially.
{
"JniPeerMembers": {
"ManagedPeerType": "WindowsAzure.Messaging.NotificationHubException, Xamarin.Azure.NotificationHubs.Android, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"JniPeerTypeName": "com/microsoft/windowsazure/messaging/NotificationHubException",
"JniPeerType": {
"PeerReference": {
"Handle": {
"value": 17866
},
"Type": 2,
"IsValid": true
},
"Name": "com/microsoft/windowsazure/messaging/NotificationHubException"
},
"InstanceMethods": {},
"InstanceFields": {},
"StaticMethods": {},
"StaticFields": {}
},
"StatusCode": 400,
"StackTrace": " at Java.Interop.JniEnvironment+InstanceMethods.CallObjectMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x0006e] in <3f19c9fc57a34ac9a473579164f8755e>:0 \n at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualObjectMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x0002a] in <3f19c9fc57a34ac9a473579164f8755e>:0 \n at WindowsAzure.Messaging.NotificationHub.Register (System.String pnsHandle, System.String[] tags) [0x00043] in <254d369ec5544bb1b606035994077f91>:0 \n at NorthNorfolk.Mobile.Client.Droid.Notifications.FirebaseService.SendRegistrationToServer (System.String token) [0x00078] in <4b8b745c15df475a92a1855a0ba61d95>:0 \n --- End of managed WindowsAzure.Messaging.NotificationHubException stack trace ---\ncom.microsoft.windowsazure.messaging.NotificationHubException\n\tat com.microsoft.windowsazure.messaging.Connection.executeRequest(Unknown Source:146)\n\tat com.microsoft.windowsazure.messaging.Connection.executeRequest(Unknown Source:134)\n\tat com.microsoft.windowsazure.messaging.Connection.executeRequest(Unknown Source:7)\n\tat com.microsoft.windowsazure.messaging.NotificationHub.upsertRegistrationInternal(Unknown Source:22)\n\tat com.microsoft.windowsazure.messaging.NotificationHub.registerInternal(Unknown Source:48)\n\tat com.microsoft.windowsazure.messaging.NotificationHub.register(Unknown Source:27)\n\tat crc64d75b20eac0c397e9.FirebaseService.n_onNewToken(Native Method)\n\tat crc64d75b20eac0c397e9.FirebaseService.onNewToken(Unknown Source:0)\n\tat com.google.firebase.messaging.FirebaseMessagingService.handleIntent(Unknown Source:53)\n\tat com.google.firebase.messaging.EnhancedIntentService.lambda$processIntent$0$EnhancedIntentService(Unknown Source:1)\n\tat com.google.firebase.messaging.EnhancedIntentService$$Lambda$0.run(Unknown Source:6)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)\n\tat com.google.android.gms.common.util.concurrent.zza.run(Unknown Source:7)\n\tat java.lang.Thread.run(Thread.java:764)\n",
"JniIdentityHashCode": 196544507,
"PeerReference": {
"Handle": {
"value": 18122
},
"Type": 2,
"IsValid": true
},
"Handle": {
"value": 18122
},
"Cause": null,
"Message": null,
"Data": {},
"InnerException": null,
"Source": "mscorlib",
"HResult": -2146233088
}
Anyone got any ideas on the above, this is driving me a bit nuts.
Notification Hub Client
I recommend using the Microsoft.Azure.NotificationHubs NuGet Package with NotificationHubClient.CreateFcmNativeRegistrationAsync to register with Notification Hubs.
Below is the code that I use to register with in my open-source App Store app, GitTrends:
https://github.com/brminnick/GitTrends/blob/c016825c792f655f3ad844908b54688aa38b3f26/GitTrends.Android/Services/NotificationService_Android.cs#L87-L98
var hubClient = NotificationHubClient.CreateClientFromConnectionString("Your Notification Hub Connection String", "Your Notification Hub Name");
await hubClient.CreateFcmNativeRegistrationAsync(token);
Google Services JSON
I also recommend ensuring you have a google-services.json file included in your Android Project. (Here's the one I use in my GitTrends app).
You are also required to add this to the Android CSPROJ file as a GoogleServicesJson item:
https://github.com/brminnick/GitTrends/blob/c016825c792f655f3ad844908b54688aa38b3f26/GitTrends.Android/GitTrends.Android.csproj#L790
<ItemGroup>
<GoogleServicesJson Include="google-services.json" />
</ItemGroup>
i'm using FCM and follow instructions on firebase site but notifications not working when app in background
i already sync gradle library and download json file and sync done but not notifications recieved when app in background
app gradle
dependencies {
///////
}
apply plugin: 'com.google.gms.google-services'
dependencies {
classpath 'com.android.tools.build:gradle:3.5.1'
classpath 'com.google.gms:google-services:4.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
You have to add
classpath 'com.android.tools.build:gradle:3.5.1'
classpath'com.google.gms:google-services:4.3.2'
in project gradle and google plugin in app gradle file.
Then add the following dependencies:
implementation 'com.google.firebase:firebase-core:17.2.0'
implementation 'com.google.firebase:firebase-messaging:19.0.0'
You need to create a service of FCM to recieve notifications.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private NotificationManager notificationManager;
private static final String ADMIN_CHANNEL_ID = "CHANNEL_ID";
#Override
public void onNewToken(String s) {
super.onNewToken( s );
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived( remoteMessage );
Map<String, String> data = remoteMessage.getData();
String body = data.get("body");
String title = data.get("title");
String image = data.get("image");
notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
setupChannels( title, body );
}
Log.d( "Notification", "onMessageReceived: " + image);
Intent notificationIntent = new Intent(this, NotificationActivity.class);
notificationIntent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP );
PendingIntent pendingIntent = PendingIntent.getService( this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT );
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder( this, ADMIN_CHANNEL_ID )
.setSmallIcon( R.drawable.ic_launcher_background )
.setContentTitle( remoteMessage.getNotification( ).getTitle( ) )
.setContentText( remoteMessage.getNotification( ).getBody( ) )
.setContentIntent( pendingIntent );
NotificationManager notificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE );
notificationManager.notify( 0, notificationBuilder.build( ) );
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void setupChannels(String adminChannelName, String adminChannelDescription) {
NotificationChannel adminChannel;
adminChannel = new NotificationChannel( ADMIN_CHANNEL_ID, adminChannelName, NotificationManager.IMPORTANCE_LOW );
adminChannel.setDescription( adminChannelDescription );
adminChannel.enableLights( true );
adminChannel.setLightColor( Color.RED );
adminChannel.enableVibration( true );
if (notificationManager != null) {
notificationManager.createNotificationChannel( adminChannel );
}
}
}
And add this code to your manifest:
<service
android:name=".MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
There are several steps for achieving the notification when application is in background.
You need to use POST parameter in Android FCM service.
You need to code down the thing inside onMessageReceived() from FCM dependencies.
https://firebase.google.com/docs/cloud-messaging/android/receive#handling_messages
because i just send notification without message body
i tried solution i just found that i forget this gradle library
implementation 'com.google.firebase:firebase-messaging:20.0.0'
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
was showing the error:
Builder (Context) in Builder cannot be applied to (FirebaseMessagingService, java.lang.String)
Help me to solve this problem.
I tried Notification.Builder notificationBuilder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID);
and
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this);
But it was not working in both API 23 and API 27.
Here is the code
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.NotificationCompat;
import com.google.firebase.messaging.RemoteMessage;
public class FirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
String notification_title = remoteMessage.getData().get("title");
String notification_msg = remoteMessage.getData().get("body");
String from_user_id = remoteMessage.getData().get("from_user_id");
String click_action = remoteMessage.getData().get("click_action");
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
String NOTIFICATION_CHANNEL_ID = "channel_id_01";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);
// Configure the notification channel.
notificationChannel.setDescription("Channel description");
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.BLUE);
notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
notificationChannel.enableVibration(true);
notificationManager.createNotificationChannel(notificationChannel);
}
Intent intent = new Intent(click_action);
intent.putExtra("user_id", from_user_id);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
notificationBuilder.setAutoCancel(true).setDefaults(Notification.DEFAULT_ALL).setWhen(System.currentTimeMillis()).setSmallIcon(R.drawable.logo1).setPriority(Notification.PRIORITY_MAX).setContentTitle(notification_title).setContentText(notification_msg).setContentInfo("Info").setContentIntent(pendingIntent);
int mNotificationId = (int) System.currentTimeMillis();
notificationManager.notify(mNotificationId, notificationBuilder.build());
}
}
build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.android.gabwithus"
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0-alpha3'
implementation 'com.android.support:design:28.0.0-alpha3'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.google.firebase:firebase-auth:16.0.2'
implementation 'com.google.firebase:firebase-core:16.0.1'
implementation 'com.google.firebase:firebase-database:16.0.1'
implementation 'com.google.firebase:firebase-messaging:17.1.0'
implementation 'com.android.support:support-v4:28.0.0-alpha3'
implementation 'com.google.firebase:firebase-storage:15.0.0'
implementation 'com.theartofdev.edmodo:android-image-cropper:2.7.0'
testImplementation 'junit:junit:4.12'
implementation 'com.squareup.picasso:picasso:2.5.2'
implementation 'com.firebaseui:firebase-ui-database:2.0.1'
implementation 'com.squareup.okhttp:okhttp:2.5.0'
implementation 'id.zelory:compressor:2.1.0'
implementation 'com.android.support:support-media-compat:28.0.0-alpha3'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'de.hdodenhof:circleimageview:2.2.0'
implementation 'com.theartofdev.edmodo:android-image-cropper:2.5.1'
implementation 'com.facebook.fresco:fresco:1.5.0'
}
apply plugin: 'com.google.gms.google-services'
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support') {
if (!requested.name.startsWith("multidex")) {
details.useVersion '25.3.0'
}
}
}
}
Try to use this, I think your problem is here: details.useVersion '25.3.0'
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == 'com.android.support') {
if (!requested.name.startsWith("multidex")) {
details.useVersion '27.1.0'
}
}
}
}
The problem is that you're using import android.support.v7.app.NotificationCompat. The v7.app.NotificationCompat was actually removed in revision 27.0.0 and was never updated to support Notification Channels.
You should remove that line and instead import android.support.v4.app.NotificationCompat, which does support Notification Channels.
its work in all api Try this :
public void sendNotification(String messageBody) {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_enable_notification_icon)
.setColor(Color.parseColor("#5878f2"))
.setContentTitle(getString(R.string.app_name))
.setContentText(messageBody)
.setAutoCancel(true);
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.putExtra("message",messageBody);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(contentIntent);
if(Build.VERSION_CODES.O <= Build.VERSION.SDK_INT) {
builder.setChannelId(createNotificationChannel());
}
Notification notification = builder.build();
notificationManager.notify(211, notification);
}
#RequiresApi(api = Build.VERSION_CODES.O)
private String createNotificationChannel(){
String channelId = "demo";
String channelName = "My demo";
NotificationChannel mChannel = new NotificationChannel(channelId,channelName, NotificationManager.IMPORTANCE_NONE);
mChannel.setImportance(NotificationManager.IMPORTANCE_HIGH);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (mNotificationManager != null) {
mNotificationManager.createNotificationChannel(mChannel);
}
return channelId;
}
Android version O and above need notification channel. here is one working example for you.getRequestCode method is for different notification so that they will not replace. you can use any number also. If you use same number notification will replace automatically, so I use a random number generator.
private static int getRequestCode() {
Random rnd = new Random();
return 100 + rnd.nextInt(900000);
}
PendingIntent pendingIntent = PendingIntent.getActivity(this, getRequestCode() /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(),
R.mipmap.ic_launcher))
.setContentTitle(neplaiTile) // use your own title
.setContentText(message) // use your own message
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
.setPriority(Notification.PRIORITY_MAX)
.setBadgeIconType(Notification.BADGE_ICON_SMALL);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "NOTIFICATION_CHANNEL_NAME", importance);
notificationChannel.enableLights(true);
notificationChannel.setLightColor(Color.RED);
notificationChannel.enableVibration(true);
notificationChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
assert notificationManager != null;
notificationBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
notificationManager.createNotificationChannel(notificationChannel);
}
assert notificationManager != null;
notificationManager.notify(getRequestCode() /* Request Code */, notificationBuilder.build());
I have this problem, I am creating an android application that is connected to Firebase. Then I have my Raspberry Pi connected to Firebase, the data sent from the Pi is GPS coordinates specifically latitude and longitude. The main application that I want to create has a Push Notification function when data on the Firebase has been changed or the coordinates on the main node has been changed. Here is the screenshot of my Firebase Data:
Firebase Database Screenshot
My problem is this, the cloud function that I created has found errors that I don't understand or I'm just overseeing it. I've looked up in the Firebase documentation, sample codes from articles and I guess nothing just seemed to work for me. Here is the code for the cloud function and the error I got when I just manually type in data in Firebase.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendLocationNotification = functions.database.ref("/GPS/{gps_id}").onWrite((event)=>{
var latitude = event.data.child('latitude');
var longitude = event.data.child('longitude');
if(!latitude.changed() && !longitude.changed()){
return console.log('The database has been reset');
}
const payload = {
notification:{
title: "Location Monitor",
body: "Your motorcycle has moved",
icon: "default",
sound: "default"
}
};
const options = {
priority: "high",
timeToLive: 60 * 60 * 24
};
return admin.messaging().sendToTopic("Location_Notification", payload, options)
});
The next one is with the Android Application, even though my Firebase FCM is in the gradle:app, then I manually send a message in the Firebase console, the application doesn't receive any messages on the avd or phone installed with the app. Here's a code for my MessagingService to handle foreground notifications:
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import java.util.Map;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "FirebaseMessgingService";
#Override
public void onMessageReceived(RemoteMessage remoteMessage){
if(remoteMessage.getData().size()>0){
Map<String, String> payload = remoteMessage.getData();
showNotification(payload);
}
}
private void showNotification(Map<String, String> payload) {
Intent intent = new Intent(this, Tracking.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
.setAutoCancel(true)
.setSmallIcon(R.drawable.track)
.setContentIntent(pendingIntent)
.setContentTitle(payload.get("Title"))
.setContentText(payload.get("Body"))
.setSound(defaultSoundUri);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0,notificationBuilder.build());
}
}
Then here's my android manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".Splash">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".Menu" />
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="#string/google_maps_key" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#drawable/track"/>
<service android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<activity
android:name=".Tracking"
android:label="#string/title_activity_tracking" />
<activity
android:name=".Tracing"
android:label="#string/title_activity_tracing" />
<activity android:name=".Tips" />
<activity android:name=".Instruction" />
<activity android:name=".About"></activity>
</application>
</manifest>
This is my gradle:app
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
defaultConfig {
applicationId ""
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.google.android.gms:play-services-maps:11.0.4'
implementation 'com.google.firebase:firebase-database:11.0.4'
implementation 'com.google.firebase:firebase-messaging:11.0.4'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
compile 'com.github.Hitomis:CircleMenu:v1.1.0'
}
apply plugin: 'com.google.gms.google-services'
Here's a the error that keeps on appearing:
TypeError: Cannot read property 'child' of undefined
at exports.sendLocationNotification.functions.database.ref.onWrite (/user_code/index.js:13:30)
at Object.<anonymous> (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:112:27)
at next (native)
at /user_code/node_modules/firebase-functions/lib/cloud-functions.js:28:71
at __awaiter (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:24:12)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:82:36)
at /var/tmp/worker/worker.js:700:26
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
As per the Firebase documentation for the onWrite method, it's passed:
a functions.Change containing a non-null functions.database.DataSnapshot and an optional non-null
functions.EventContext)
However in your function you're expecting an event object, which results empty.
Following the sample code available here, you could re-write your function like so:
exports.makeUppercase = functions.database.ref("/GPS/{gps_id}")
.onWrite((change, context) => {
// You can get the previous value for latitude and longitude
var previousLatitude = change.before.ref.parent.child('latitude');
var previousLongitude = change.before.ref.parent.child('longitude');
// And the new values
var newLatitude = change.after.ref.parent.child('latitude');
var newLongitude = change.after.ref.parent.child('longitude');
// And perform your logic from here
...
return admin.messaging().sendToTopic("Location_Notification", payload, options);
});
I haven't checked the Android issue you mentioned but I guess that since the Firebase Function was failing, the return statement didn't execute and no notification was sent at all.
I am trying to implement FCM in my app. Right now, I am able to receive messages when i send them from firebase app console. But when i try to send messages from my server, the message is not getting delivered to the phone. However, I am getting a success status after sending message from the server and it shows delivered to 1 device. Any help would be appreciated.
Thanks.
Manifest File:
</application>
<service
android:name=".FirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name=".FirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
</manifest>
Build.gradle app:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.android.support:design:24.0.0'
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.google.firebase:firebase-messaging:9.0.2'
}
apply plugin: 'com.google.gms.google-services'
Build.gradle project:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.2'
classpath 'com.google.gms:google-services:3.0.0'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Code:
public class FirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
ShowNotification(remoteMessage.getData().get("message"));
}
private void ShowNotification(String message) {
Intent i = new Intent(this,MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingintent = PendingIntent.getActivity(this,0,i,PendingIntent.FLAG_UPDATE_CURRENT);
android.support.v4.app.NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setAutoCancel(true)
.setContentTitle("FCM Test")
.setContentText(message)
.setSmallIcon(R.drawable.common_google_signin_btn_icon_dark)
.setContentIntent(pendingintent);
NotificationManagerCompat manager =(NotificationManagerCompat) getSystemService(NOTIFICATION_SERVICE);
manager.notify(0,builder.build());
}
}
public class FirebaseInstanceIDService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
String token = FirebaseInstanceId.getInstance().getToken();
System.out.println("TOKEN " + token);
}
}
Server Side Code:
function send_notification ($tokens, $message)
{
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'registration_ids' => $tokens,
'data' => $message
);
$headers = array(
'Authorization:key = ***********************************',
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
if ($result === FALSE) {
die('Curl failed: ' . curl_error($ch));
}
curl_close($ch);
return $result;
}
$tokens = array();
$tokens[] = "***********************************************";
$message = array("message" => " DEEPAK PUSH TEST MESSAGE");
$message_status = send_notification($tokens, $message);
echo $message_status;
I was able to fix the issue. The format in which I was generating json, was wrong. I didnt put the payload under notification tag. Post that change it started working. Thanks a lot guys, for all your suggestions.