I am developing Firebase push notification using Server API call in Android application.it works perfectly when application is in foreground but when application is not in foreground i am not able to get the push notification.
I am sending JSON data in which header contains Server API key and content type and the value contains data which have body as array. Appreciate any help.
PHP code:
$url = 'https://fcm.googleapis.com/fcm/send';
$fields =array('registration_ids' => $tokens,'data' => $message);
$headers = array('Authorization:key = value','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);?>
Look at my code. Maybe it will help you:
$token = getTokenDevice($dn);
$path_to_firebase_cm = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'to' => $token,
'priority' => 'normal',
'content_available' => true,
'data' => array('type' => $type, 'title' => $title, 'body' => $message)
);
$headers = array(
'Authorization:key='.$server_key,
'Content-Type:application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $path_to_firebase_cm);
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_IPRESOLVE, CURL_IPRESOLVE_V4 );
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
curl_close($ch);
I use content_available for iOS devices. That code works for me in Android and iOS when apps are in background.
So you should check your FirebaseMessaging service. Mine looks like this:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Auth auth = new Auth(getApplicationContext());
Map<String, String> data = remoteMessage.getData();
if (auth.isNotificationEnabled(data.get("type"))) {
Log.e(TAG, "data: " + remoteMessage.getData());
sendNotification(data.get("title"), data.get("body"));
}
}
I too felt this was happening in the beginning but then discovered that my Android App was indeed waking up. Unfortunately it was not waking up enough to do what I wanted (send a heartbeat REST message to my Server). So I will answer your question with a question - why did you decide you did not get a push notification ? For me, when I logged messages from within the onMessageReceived ....
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
Log.d(TAG, "Notification Message Body: " + remoteMessage.getData());
}
It proved the App got woken up each time the Fire Cloud Messaging service sent a message, regardless if the App was in foreground or background.
Other mistakes, I made initially I shall share with you:
I had to make some changes to my Server side to ensure that the Android App onMessageReceived() method was always called even in background mode. My messages were JSON and HTTP and Upstream. My server is written in C#.
In Firebase there are 2 types of payload downstream messaging. (a) Notification and (b) Data. The type depicts how the App behave when receiving messages depend on whether the app is in background or the foreground. Hence I needed (b) Data type payload to meet my requirement. Just add the “data”
I then had to make my messages High Priority rather than normal. I did a load of tests with both normal and high. Normal did not work once the Android App went into Doze mode. I found this reference useful. https://developer.android.com/training/monitoring-device-state/doze-standby.html#support_for_other_use_cases
Related
I try to implement FCM in my app but I have a problem. Whenever I send the notification, instead of calling my custom code, it just show the default notification. What am I doing wrong?
Those are the services:
<service
android:name="com.backgroundws.MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name="com.backgroundws.MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
And this is my Java code:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d("MyFirebaseMessaging", "GotMessage");
WSListener.sendEvent(this, "Push");
}
}
And I see this in the logcat when I get the notification on the device:
I/SendBroadcastPermission: action:com.google.android.gms.gcm.ACTION_SCHEDULE, mPermissionType:0
I/SendBroadcastPermission: action:com.google.android.gms.gcm.ACTION_SCHEDULE, mPermissionType:0
This is how I send the notifications:
function send_gcm_notify($reg_id, $message, $url, $key) {
$fields = array(
'to' => $reg_id ,
'priority' => "high",
"notification" => array("body"=>$message),
'data' => array( "url"=> $url)
);
$headers = array(
'Content-Type: application/json',
'Authorization: key=' . $key
);
$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);
if ($result === FALSE) {
//die('Problem occurred: ' . curl_error($ch));
}
curl_close($ch);
return $result;
}
Of course I tested and the path to the service is correct.
If you want your server's content with notification in both modes(Background and Foreground), You have to send payload from server inside 'data' only.
For more you can refer here How to handle Android FCM Messages when application is in Background with data payload?
I just need to send push notifications to a handful of devices. I have their device tokens in an array. Do I need to create topics or groups for this?
I can send push notifications individually using a for loop, but is there a better way to do this?
EDIT: Please do not mark this question as duplicate without understanding. The question
FCM (Firebase Cloud Messaging) Send to multiple devices
has answers to use FCM Token and groups, which I have clearly stated that is not my requirement. As far as 'registration_ids' mentioned by other question is concerned its not mentioned anywhere in the official docs , if it is mentioned then please point it out as a valid answer.
Use "registration_ids" instead of "to".
var message = {
registration_ids:['id1','id2','id3'],
notification: {
title: 'Hello There...!',
body: 'this is test notification'
}
};
Hope It Works..!!!
I know this has been answered and not a very latest question.
Sure, you can construct the string array and send it like this as mentioned in the google documentation find here.
HTTP POST request
For example, to add a device with the registration ID 51 to appUser-Chris, you would send this request:
{
"operation": "add",
"notification_key_name": "appUser-Chris",
"notification_key": "APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ",
"registration_ids": ["51"] //you can insert something more of your strings here.
}
Response format
A successful request to either add or remove a device returns a notification_key like the following:
{
"notification_key": "APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ"
}
<?php
// Your code here!
class FCM
{
private $key;
function __construct($api_key)
{
$this->key = $api_key;
}
/**
* Sending Push Notification
*/
public function send_notification($registatoin_ids, $notification)
{
$fields = array ( 'to' => $registatoin_ids,'notification' => $notification); //'restricted_package_name' => "com.apps.firebasenotificationphp");
$headers = array (
'Authorization: key=' . $this->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_POSTFIELDS, json_encode($fields) );
return curl_exec ( $ch );
curl_close ( $ch );
}
}
$api_key = "";
$device_id = "";
$fcm = new FCM($api_key);
$arrNotification = array ("body" => "hii","title" => "hello",'image' => "https://www.gstatic.com/devrel-devsite/prod/vb1c70bbe2f68b543db3deb1075af42e62f8f21e5fc703b8398dc6b9860f1711f/firebase/images/lockup.png",'link' => "",'sound' => "default");
echo $fcm->send_notification($device_id,$arrNotification);
?>
I am trying to use cordova fcm plugin on Android to implement the data sent by Firebase Cloud Messaging. I successfully received the notifications, but when I tap them they are not giving the alert I want.
Here is the code used in index.js:
onDeviceReady: function() {
app.receivedEvent('deviceready');
FCMPlugin.onNotification(
function(data){
if(data.wasTapped){
//Notification was received on device tray and tapped by the user.
alert( JSON.stringify(data) );
}else{
//Notification was received in foreground. Maybe the user needs to be notified.
alert( JSON.stringify(data) );
}
},
function(msg){
alert('onNotification callback successfully registered: ' + msg);
},
function(err){
alert('Error registering onNotification callback: ' + err);
}
);
},
And here is the php code I used to send the notification:
function pushAndroidNotification ($productUrl, $message, $deviceToken) {
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'registration_ids' => array($deviceToken),
'notification' => array(
"title" => "rBUX",
"body" => $message,
"icon" => "name_of_icon" ),
'data' => array("url" => $productUrl)
);
$jfields = json_encode($fields);
echo "\r\n<br>Post json:".$jfields;
$headers = array(
'Authorization: key = AIzaSyBPRoJ7zgmevPYIzoDweVgNTbmsPBW5ofo',
'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, $jfields);
$result = curl_exec($ch);
if ($result === FALSE) {
echo "\r\n<br>Notify Failed:".curl_error($ch);
die('Curl failed: '.curl_error($ch));
}else{
echo "\r\n<br>Notify passed:".$result;
}
$jresponse = json_decode($result, true);
curl_close($ch);
return $jresponse;
}
But every time I launch the app, I can see the alert "onNotification callback successfully registered: OK", so the FCM plugin is not completely disabled.
I would like to launch the url when I tap on the notification, but for now it appears that I can't even use the data. If anyone knows how to solve this please tell me, and please let me know how to use stringified data to launch the url in cordova inAppBrowser, thank you.
For "cordova-plugin-fcm" plugin, You need to set click_action to FCM_PLUGIN_ACTIVITY in the notification payload part.
I got the following from their website:
{
"notification":{
"title":"Notification title", //Any value
"body":"Notification body", //Any value
"sound":"default", //If you want notification sound
"click_action":"FCM_PLUGIN_ACTIVITY", //Must be present for Android
"icon":"fcm_push_icon" //White icon Android resource
},
"data":{
"param1":"value1", //Any data to be retrieved in the notification callback
"param2":"value2"
},
"to":"/topics/topicExample", //Topic or single device
"priority":"high", //If not set, notification won't be delivered on completely closed iOS app
"restricted_package_name":"" //Optional. Set for application filtering
}
I'm trying to send a non-collapse message via Google Cloud Messaging. For some reason a new message always replaces the previous one. I've tried to use different collapse-keys with no effect. Also omitting the collapse key does not work. What could be the problem?
This is an example code:
<?php
$ids[] = '<notification registration id of the test phone>';
sendNotification($ids, "test message 1", "key1");
sendNotification($ids, "test message 2", "key2");
function sendNotification($ids, $message, $collapseKey)
{
$apiKey = '<api key here>';
$url = 'https://android.googleapis.com/gcm/send';
$data['title'] = 'AppName';
$data['message'] = $message;
$post['registration_ids'] = $ids;
$post['data'] = $data;
if ($collapseKey) {
$post['collapse_key'] = $collapseKey;
}
$headers = array(
'Authorization: key=' . $apiKey,
'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_POSTFIELDS, json_encode( $post ) );
$result = curl_exec( $ch );
if ( curl_errno( $ch ) )
{
echo 'GCM error: ' . curl_error( $ch );
}
curl_close( $ch );
echo $result;
}
?>
From the GCM collapse key documentation, omitting the collapse-key should prevent replacing the old messages. Unless some of your messages already expired or your devices are not connected.
Also, the NOTIFICATION_ID with notify method call is implemented in your client application, not your service side code. So it should not be mattered if you are using HTTP server. You can refer to this documentation about NOTIFICATION_ID in your client application's broadcast receiver. Also this StackOverflow answer about how to generate unique NOTIFICATION_ID.
I am going to answer my own question.
There are two scenarios:
For instance: you send two messages when your phone is offline (no wifi, no data, turned off)
Background/killed app -
I only get one notification, but actually i get the two data-message
Foreground -
I get the two notification
Please remember not to add "collapse_key" parameter.
Hope this can help anyone else with the same problem.
I am running the Google GCM test code from here and it runs on both emulator and phone, however when I do a send message the notification only works on the emulator and not the phone.
GCMIntentService Notifcation
import android.support.v4.app.NotificationCompat;
...
// issues a notification to inform the user that server has sent a message
private void generateNotification(Context context, String message) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context).setSmallIcon(R.drawable.ic_launcher)
.setTicker(context.getString(R.string.app_name)).setContentText(message);
Intent notificationIntent = new Intent(context, Main.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(contentIntent);
// add notification
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(FM_NOTIFICATION_ID, builder.build());
}
PHP Send message and send function
require_once 'push_db_functions.php';
$dbf = new push_db_functions();
$id = '40';
$message = "Test Message";
$response = $dbf->sendMessage($id, $message);
$response = json_decode($response);
print_r($response);
public function sendMessage($id, $message) {
$results = mysql_query("SELECT regid FROM test WHERE id = '$id'");
$processed = mysql_fetch_row($results);
$url = 'https://android.googleapis.com/gcm/send';
$apiKey = "AIzaSyD-xxx";
$fields = array('registration_ids' => $processed, 'data' => array( "message" => $message),);
$headers = array('Authorization: key=' . $apiKey, 'Content-Type: application/json');
// open connection
$ch = curl_init();
// set the url, number of POST vars, POST data
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_POSTFIELDS, json_encode($fields));
// execute post
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
Send message response
stdClass Object ( [multicast_id] => 5036849453049739126 [success] => 1 [failure] => 0 [canonical_ids] => 0 [results] => Array ( [0] => stdClass Object ( [message_id] => 0:1353799902066759%04108f12f9fd7ecd ) ) ) success
I have 2 regId records in my database, one for the emulator and one for the phone $id 39 and 40 and change them accordingly to send messages to either device.
Database records
id | regid
39 | APA91bFyMJx4b0ddI........ Emulator
40 | APA91bFhwEhHOClkg........ Phone
The phone is running Gingerbread and the program registers and runs correctly on it except for not displaying the notification upon message receipt.
mDisplay = (TextView) findViewById(R.id.display);
registerReceiver(mHandleMessageReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION));
final String regId = GCMRegistrar.getRegistrationId(this);
Log.d("registrationID", "::" + regId);
if (regId.equals("")) {
// automatically registers application on startup.
GCMRegistrar.register(this, SENDER_ID);
}
Any help would be greatly appreciated.
Thanks
Thank you for everyone that responded to this question.
I have resolved the issue:
On my phone under Accounts & Sync, General sync settings, I found that the Background data sync box was not ticked. When set all works fine.
I should have figured this out before asking the question, my apologies.
However I hope this answer can be of assistance to others.