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.
Related
I have a little problem here that I, unfortunately, I currently can't really solve it by myself, so asking for help here.
I am trying to build push notifications in my app and I am using FCM.
For this whole process I use:
Android application with firebase
PHP Script to send FCM Push Notifications
MySQL DB to store tokens.
It works the following way: Each time a new token is generated, I send this token to my MySQL db where it is then stored. A PHP script that I have reads db for all tokens that it can find and sends push notification to all the devices.
I have watched many youtube videos and read multiple articles on how to do that and I managed to get it working, however, it is quite unstable and I can't get it to work persistently.
Here are some scenarios where it doesn't work for unknown to me reason.
Case 1:
Day 1:
I just installed application, launched it and then put it in background. Sent Push and received it successfully. In 3-4 hours I send notification again and successfully receive it.
Day 2: Right after Day 1, at 1 AM in the morning of Day 2 I sent notification again and it was never received. I went to bed and in the morning the message was never received still so I tried to send message again and my php script says that message was received (as per Firebase console response), but the notification is never shown.
-- Note: I have also implemented a method inside "onMessageReceived()" to save the message to MySQL so that I can personally monitor if the device at least received the message to better understand how it works, but the device never even received it.
Case 2:
Day 1: Installed application. Launched it, closed it and sent Push. Successfully received.
In 1 hour, I reboot my phone. 20 mins later I tried sending Push but I never received it. I tried launching application and putting it in background, yet I still received nothing.
I tried sending some Notifications not with PHP script, but with FCM Console, but still nothing.
Only after 10 minutes I received Notifications that I send some time ago, yet I tried sending notifications with my PHP script and it still didn't work and only after few more minutes I could send notifications with my PHP again.
The behavior that I described above is simply very chaotic to my understanding. I don't follow any logic whatsoever.
My Code:
PHP Script:
<?php
function send_notification ($tokens, $data, $priority)
{
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'delay_while_idle' => false,
'android' => $priority,
'data' => $data,
'registration_ids' => $tokens
);
//var_dump($fields);
$headers = array(
'Authorization: key = KJAdkashdkhaiiwueyIhAXZ.....',
'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);
print($ch);
print("<br>");
print("<br>");
print($result);
print("<br>");
print("<br>");
print(json_encode($fields));
print("<br>");
print("<br>");
if ($result === FALSE) {
die('Curl failed: ' . curl_error($ch));
}
curl_close($ch);
return $result;
}
$conn = mysqli_connect('ip_address', 'username', "password", 'mydatabasename');
$sql = "SELECT TOKEN FROM users";
$result = mysqli_query($conn,$sql);
$tokens = array();
if(mysqli_num_rows($result) > 0 ){
while ($row = mysqli_fetch_assoc($result)) {
$tokens[] = $row["TOKEN"];
}
}
mysqli_close($conn);
$data = array(
'title' => 'This is title of the message',
'body' => 'This is body of the message',
'contents' => 'Simple contents of the message'
);
$android = array(
'priority' => 'high'
);
$message_status = send_notification($tokens, $data, $android);
echo $message_status;
Android:
MyFirebaseMessagingService
class MyFirebaseMessagingService : FirebaseMessagingService() {
/**
* Called when message is received.
*
* #param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
override fun onMessageReceived(remoteMessage: RemoteMessage) {
// Save received message to MySQL
HUC.success()
// Check if message contains a data payload.
if (remoteMessage.data.isNotEmpty()) {
Log.d(TAG, "Message data payload: ${remoteMessage.data}")
}
// Check if message contains a notification payload.
remoteMessage.notification?.let {
Log.d(TAG, "Message Notification Body: ${it.body}")
}
// Send notification containing the body of data payload
sendNotification(remoteMessage.data["body"].toString())
}
// [END receive_message]
// [START on_new_token]
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
override fun onNewToken(token: String) {
Log.d(TAG, "Refreshed token: $token")
// Saving my registration token to MySQL
sendRegistrationToServer(token)
}
// [END on_new_token]
/**
* Persist token to third-party servers.
*
* Modify this method to associate the user's FCM InstanceID token with any server-side account
* maintained by your application.
*
* #param token The new token.
*/
private fun sendRegistrationToServer(token: String?) {
CoroutineScope(IO).launch {
// HttpURLConnection function to save token to MySQL
val response = HUC.saveToken(token)
withContext(Main){
Log.d(TAG, "Server response: $response")
}
}
}
/**
* Create and show a simple notification containing the received FCM message.
*
* #param messageBody FCM message body received.
*/
private fun sendNotification(messageBody: String) {
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(
this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT
)
val channelId = getString(R.string.default_notification_channel_id)
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(getString(R.string.fcm_message))
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
channelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_HIGH
)
notificationManager.createNotificationChannel(channel)
}
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build())
}
companion object {
private const val TAG = "MyFirebaseMsgService"
}
}
Please help me understand here. Maybe I am doing something wrong or perhaps I am missing something.
As a matter of fact, everything started working properly when I hard reset my phone which leads me to believe that it was internal phone problem rather than my implementation.
I am able to send notification when app is in foreground and background. But cant manage to send it when app is killed i.e app not running in background. Other app in my mobile are able to send me notification even when they are running in background. I am using oreo version.
I too replaced 'notification' with 'data' which didnt made a difference.
I already added the custom notification on onMessageReceived method, the 'notification' and 'data' both gives notification on foreground and background. Only difference is 'data' runs onMessageReceived method while on background too. But on both , notification is not received when app is killed.I have tried following code on php. What am i doing wrong?
function sendPushNotification($token) {
$url = "https://fcm.googleapis.com/fcm/send";
$serverKey = 'AAAA.....theKey';
$title = "My App";
$body = "hello there!!";
$notification = array('title' =>$title , 'body' => $body, 'sound' => 'default', 'badge' => '1');
$arrayToSend = array('to' => $token, 'notification' => $notification,'priority'=>'high');
$json = json_encode($arrayToSend);
$headers = array();
$headers[] = 'Content-Type: application/json';
$headers[] = 'Authorization: key='. $serverKey;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST,"POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);
//Send the request
$response = curl_exec($ch);
//Close request
/* if ($response === FALSE) {
die('FCM Send Error: ' . curl_error($ch));
}*/
curl_close($ch);
// echo "<br>";
return $response;
}
Following in onMessageReceived method:
For 'notification':
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d("apkflow","onMessageReceived Started");
if (remoteMessage.getNotification() != null) {
title = remoteMessage.getNotification().getTitle();
body = remoteMessage.getNotification().getBody();
Log.d("apkflow","title = " + title);
Log.d("apkflow","body = " + body);
}
}
For 'data':
title = remoteMessage.getData().get("title");
body = remoteMessage.getData().get("body");
UPDATE::
I got the solution now !! Its due to the mobile recents updates. In mobiles like Vivo, oppo, xiomi and so on , when app is cleared, it force stop the app forcing to stop all the services. So, the FCM services is also stopped and no any notification is received on mobile. So, for getting notification, user must allow the app to run in background "allow in background" must be checked. This solves the problem. If you still have problem , leave a comment!!
Messages with both notification and data payload, when received in the
background.
Change the notification type data
$arrayToSend = array('to' => $token, 'data' => $notification,'priority'=>'high');
Please go through the below documentation
https://firebase.google.com/docs/cloud-messaging/android/receive
You have to create the custom notification.
private void setNotification(RemoteMessage content) {
Log.d(TAG, "custom notification: ");
Intent intent = new Intent(this, NotificationActivity.class);
if (!content.getData().get("url").isEmpty())
intent.putExtra("url", content.getData().get("url"));
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setAction(Long.toString(System.currentTimeMillis()));
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);
RemoteViews remoteViews = new RemoteViews(getPackageName(),
R.layout.custome_notification);
remoteViews.setTextViewText(R.id.tvTime, currentDate());
remoteViews.setTextViewText(R.id.text, content.getData().get("text"));
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, getPackageName())
.setSmallIcon(R.drawable.ic_alert)
.setContent(remoteViews)
.setAutoCancel(true)
.setSound(defaultSoundUri);
notificationBuilder.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// To avoid replacing old notification by new one. To set new id for every new Notification following notifications.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = new NotificationChannel(getPackageName(), "AppName", importance);
notificationManager.createNotificationChannel(mChannel);
}
int notifyId = (int) System.currentTimeMillis();
notificationManager.notify(notifyId, notificationBuilder.build());
}
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 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
I have device token "apid" from android phone. I get the valid response that notification is send. but i dont receive the notification. can some one please guide me i am using the following code. i am using php for sending notification
$contents = array();
$contents['alert'] = 'test notification for android';
$notification = array();
$notification['android'] = $contents;
$platform = array();
array_push($platform, "android");
$dev['apid'] = 'valid_device_token_from_android' ;
$push = array("audience"=> $dev, "notification"=>$notification, "device_types"=>$platform);
$json = json_encode($push);
echo "Payload: " . $json . "\n"; //show the payload
$session = curl_init(PUSHURL);
curl_setopt($session, CURLOPT_USERPWD, APPKEY . ':' . PUSHSECRET);
curl_setopt($session, CURLOPT_POST, True);
curl_setopt($session, CURLOPT_POSTFIELDS, $json);
curl_setopt($session, CURLOPT_HEADER, False);
curl_setopt($session, CURLOPT_RETURNTRANSFER, True);
curl_setopt($session, CURLOPT_HTTPHEADER, array('Content-Type:application/json', 'Accept: application/vnd.urbanairship+json; version=3;'));
$content = curl_exec($session);
echo "Response: " . $content . "\n";
Thanks