Unable to send notification to multiple devices using FCM - php

I'm getting a notification only in one device that is set as the first token stored the table in mySQL DB and the notification is not sent to the rest of the token numbers. I tried a WHILE loop and stored the token numbers in an array, but it did not work.
Please suggest a solution. Thank you.
Here is my code:
<?php
require "init.php";
$message=$_POST['message'];
$title=$_POST['title'];
$path_to_fcm='https://fcm.googleapis.com/fcm/send';
$server_key="A*************************Q";
$sql="select token from fcm_info";
$result =mysqli_query($con,$sql);
$row=mysqli_fetch_row($result);
$key=$row[0];
$headers = array(
'Authorization:key=' .$server_key,
'Content-Type:application/json'
);
$fields =array('to'=>$key,
'notification'=>array('title'=>$title,'body'=>$message));
$payload =json_encode($fields);
$curl_session =curl_init();
curl_setopt($curl_session,CURLOPT_URL, $path_to_fcm);
curl_setopt($curl_session,CURLOPT_POST, true);
curl_setopt($curl_session,CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl_session,CURLOPT_RETURNTRANSFER,true);
curl_setopt($curl_session,CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl_session,CURLOPT_IPRESOLVE, CURLOPT_IPRESOLVE);
curl_setopt($curl_session,CURLOPT_POSTFIELDS, $payload);
$result=curl_exec($curl_session);
curl_close($curl_session);
mysqli_close($con);
?>

Use 'registration_ids' instead of 'to' and pass comma separated multiple registrations ids to use multicast in FCM. Final payload should be like:
{
"registration_ids":["id1","id2",...],
"priority" : "normal",
"data" : {
"title" : "Title",
"message" : "Message to be send",
"icon": "icon_path"
}
}
see https://developers.google.com/cloud-messaging/http-server-ref for more help

////////////////////// FCM START /////////////////////////
$path_to_fcm = "https://fcm.googleapis.com/fcm/send";
$server_key = "your_server_key";
$headers = array(
'Authorization:key=' . $server_key,
'Content-Type:application/json');
$keys = ["key_1", "key_2"];
$fields = array(
"registration_ids" => $keys,
"priority" => "normal",
'notification' => array(
'title' => "title of notification",
'body' => "your notification goes here"
)
);
$payload = json_encode($fields);
$curl_session = curl_init();
curl_setopt($curl_session, CURLOPT_URL, $path_to_fcm);
curl_setopt($curl_session, CURLOPT_POST, true);
curl_setopt($curl_session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_session, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl_session, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_setopt($curl_session, CURLOPT_POSTFIELDS, $payload);
$curl_result = curl_exec($curl_session);
////////////////////// FCM END /////////////////////////
This works for me.

You need to cover the notification sending logic in method and then start the loop & call that method in each iterations pass token and message to the method.

"Please suggest a solution"
I would like to suggest using Services. You're most recommended to read the documention by Android Studio here.
There is a lot to perceive about Services, but at the moment I believe a snippet will be most helpful to you, here is a little code,
Create a class called HelloService
and paste the following code inside with the proper imports*
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "servicestarting",Toast.LENGTH_SHORT).show();
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
"This is overhwleming" you might think to yourself. However it's but the contrary.
Example for Services + Firebase
Instead of pushing a message from Firebase, let's say you want to notify a user whenever a modification takes place in one of your databases
first, create databasereference earlier on the Oncreate
mDatabaseLike=FirebaseDatabase.getInstance().getReference().child("Likes");
Go to 'handleMessage Method' and add the following
#Override
public void handleMessage(Message msg) {
mDatabaseLike.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
notifyUserOfDBupdate()
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
//stopSelf(msg.arg1);
}
}
Here is the notifyUserOfDBupdate method and how to notify a user
private void notifyUserOfDBupdate() {
//Intents
Intent Pdf_view = new Intent(this, //class to throw the user when they hit on notification\\.class);
PendingIntent pdf_view = PendingIntent.getActivity(this, 0, Pdf_view, 0);
//Notification Manager
NotificationManager nm = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
//The note
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Notification noti = new NotificationCompat.Builder(getApplicationContext())
.setTicker("TickerTitle")
.setContentTitle("content title")
.setSound(soundUri)
.setContentText("content text")
.setContentIntent(pdf_view).getNotification();
//Execution
noti.flags = Notification.FLAG_AUTO_CANCEL;
nm.notify(0, noti);
}
Now run your application once on your real device and a second time on an emulator. Once either one of two modifies your firebase database, the other will be notified instantly.
Modify whichever method you like inside the HandleMessage method. It will be eternal, not unless you make it killable.
kindest regards

Related

Azure Marketplace SaaS fulfilment API- resolving subscription - PHP

I am trying to resolve an azure marketplace subscription using the azure fulfilment api. I have followed the instructions on the Microsoft's SaaS fulfilment api's docs but I am not able to resolve the subscription using PHP.
I am able to get access_token and incidentally I am able to use the token and and use this together with the purchase identification token i get from azure portal when the subscriber is re-directed to the SaaS landing page, to get a successful json response when using postman.
I cannot achieve the same success when using PHP. I get a 403 error - Authorization is missing, incorrect or invalid. I am thinking that the query string bit of authorization parameter is malformed. This has nothing to do with privileges or permissions as I am able to get a successful output on Postman. Here is the code
<?php
use Microsoft\Graph\Graph;
use Microsoft\Graph\Http;
use Microsoft\Graph\Model;
use GuzzleHttp\Client;
class GraphHelper {
private static Client $tokenClient;
private static Client $tokenWebClient;
private static string $clientId = '';
private static string $tenantId = '';
private static string $clientSec = '';
private static string $graphUserScopes = '';
private static Graph $userClient;
private static string $userToken;
private static string $resolveToken;
private static string $subToken= '';
public static function initializeGraphForUserAuth(): void {
GraphHelper::$tokenClient = new Client();
GraphHelper::$clientId = $_ENV['CLIENT_ID'];
GraphHelper::$clientSec = $_ENV['CLIENT_SECRET'];
GraphHelper::$tenantId = $_ENV['TENANT_ID'];
GraphHelper::$graphUserScopes = $_ENV['GRAPH_USER_SCOPES'];
GraphHelper::$userClient = new Graph();
}
public static function getUserToken(): void {
//getting the access token
$accessCodeRequestUrl = 'https://login.microsoftonline.com/'.GraphHelper::$tenantId.'/oauth2/token';
$tokenRequestUrl = 'https://marketplaceapi.microsoft.com/api/saas/subscriptions/resolve?api-version=2018-08-31';
$subToken = $_SESSION['subToken'];
$tokenResponse = GraphHelper::$tokenClient->post($accessCodeRequestUrl, [
'form_params' => [
'client_id' => GraphHelper::$clientId,
'grant_type' => 'client_credentials',
'client_secret' => GraphHelper::$clientSec,
'resource' => '20e940b3-4c77-4b0b-9a53-9e16a1b010a7'
],
// These options are needed to enable getting
// the response body from a 4xx response
'http_errors' => false,
'curl' => [
CURLOPT_FAILONERROR => false
]
]);
if ($tokenResponse->getStatusCode() == 200) {
// Return the access_token
$responseBody = json_decode($tokenResponse->getBody()->getContents());
GraphHelper::$resolveToken = $responseBody->access_token;
$resolveAccessToken= $responseBody->access_token;
} else if ($tokenResponse->getStatusCode() == 400) {
// Check the error in the response body
$responseBody = json_decode($tokenResponse->getBody()->getContents());
if (isset($responseBody->error)) {
$error = $responseBody->error;
// authorization_pending means we should keep polling
if (strcmp($error, 'authorization_pending') != 0) {
throw new Exception('Token endpoint returned '.$error, 100);
}
}
}
//resolving the subscription
$resolveResponse = GraphHelper::$tokenClient->post($tokenRequestUrl, [
'form_params' => [
'content-type' => 'application/json',
'authorization' => 'Bearer '.$resolveAccessToken,
'x-ms-marketplace-token'=> $subToken
],
// These options are needed to enable getting
// the response body from a 4xx response
'http_errors' => false,
'curl' => [
CURLOPT_FAILONERROR => false
]
]);
//test whether there is a reponse
return $resolveResponse->getStatusCode(); // this returns a 403 - Authorization is missing, incorrect or invalid.
}
}
?>
I figured out that I needed to use cUrl for option to include authorization and other headers. Postman did this automatically hence the reason I was able to get results with postman and not with PHP. Eventually this code did it for me.
$subToken = rawurldecode($_SESSION['subToken']);
$ch = curl_init ();
curl_setopt ($ch, CURLOPT_URL, $tokenRequestUrl);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_HTTPHEADER, array ('Authorization: Bearer '.GraphHelper::$resolveToken,
'Content-type: application/json',
'X-ms-marketplace-token:'. $subToken));
curl_setopt($ch, CURLOPT_POST, true);
$results = json_decode (curl_exec ($ch), 1);
if (array_key_exists ('error', $results)){
echo ($results['error']);
die();
}
curl_close($ch);
return $results['subscriptionName'] ;
I found out that the endpoint was not accepting a get request. It threw an error of Subscription resolve not found","target":"subscriptionId","code":"EntityNotFound . However including a post option corrected that and no error was thrown after this. Again when decoding the token from the url - don't use urldecode() use rawurldecode () instead.

Checksum mismatch error paytm payment integration

I am trying to implement Paytm payment gateway in my app but it is giving
Bundle[{STATUS=TXN_FAILURE, ORDERID=order1, TXNAMOUNT=7.00, MID=cdBOMy65033449597261, RESPCODE=330, BANKTXNID=, CURRENCY=INR, RESPMSG=Paytm checksum mismatch.}] this error, for both TEST and Production environment.
Here is my PHP code to generate the checksum.
$paytmParams = array();
$paytmParams["MID"] = "cdBOMy65033449597261";
$paytmParams["ORDER_ID"] = "order1";
$paytmParams["CUST_ID"] = "cust1";
$paytmParams["MOBILE_NO"] = "9799990168";
$paytmParams["EMAIL"] = "droidwithme#gmail.com";
$paytmParams["CHANNEL_ID"] = "WAP";
$paytmParams["TXN_AMOUNT"] = "7.00";
$paytmParams["WEBSITE"] = "DEFAULT"; //tried WEBSTAGING and APPSTAGING
$paytmParams["INDUSTRY_TYPE_ID"] = "Retail";
$paytmParams["CALLBACK_URL"] = "https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=order1";
//Here checksum string will return by getChecksumFromArray() function.
$paytmChecksum = EndecPaytm::getChecksumFromArray($paytmParams, $merchantKey);
$responseBody = [
'message' => 'Checksum Generated.',
'data' => [
"CHECKSUMHASH" => $paytmChecksum,
"ORDER_ID" => "order1",
"payt_STATUS" => "1"
]
];
return ApiMethods::apiResponse('success', $responseBody);
And this is my android side code,
private void getPaytmWindow(String chkSm) {
PaytmPGService Service = PaytmPGService.getProductionService();
//Kindly create complete Map and checksum on your server-side and then put it here in paramMap.
HashMap<String, String> paramMap = new HashMap<>();
paramMap.put( "MID" , "cdBOMy65033449597261"); //cdBOMy65033449597261
// Key in your staging and production MID available in your dashboard
paramMap.put( "ORDER_ID" , "order1");
paramMap.put( "CUST_ID" , "cust1");
paramMap.put( "MOBILE_NO" , "9799990168");
paramMap.put( "EMAIL" , "droidwithme#gmail.com");
paramMap.put( "CHANNEL_ID" , "WAP");
paramMap.put( "TXN_AMOUNT" , "7.00");
paramMap.put( "WEBSITE" , "DEFAULT");
// This is the staging value. Production value is available in your dashboard
paramMap.put( "INDUSTRY_TYPE_ID" , "Retail");
// This is the staging value. Production value is available in your dashboard
paramMap.put( "CALLBACK_URL", "https://securegw.paytm.in/theia/paytmCallback?ORDER_ID=order1");
paramMap.put( "CHECKSUMHASH" , chkSm);
PaytmOrder Order = new PaytmOrder(paramMap);
Service.initialize(Order, null);
Service.startPaymentTransaction(this, true, true,
new PaytmPaymentTransactionCallback() {
#Override
public void someUIErrorOccurred(String inErrorMessage) {
// Some UI Error Occurred in Payment Gateway Activity.
// // This may be due to initialization of views in
// Payment Gateway Activity or may be due to //
// initialization of webview. // Error Message details
// the error occurred.
Utils.logD(TAG, "someUIErrorOccurred : " + inErrorMessage);
}
#Override
public void onTransactionResponse(Bundle inResponse) {
Log.d("LOG123444", "Payment Transaction : " + inResponse);
if (Objects.requireNonNull(inResponse.getString("STATUS")).contains("TXN_SUCCESS")) {
Toast.makeText(getApplicationContext(), "Transaction completed", Toast.LENGTH_LONG).show();
}
Utils.logD(TAG, inResponse.getString("STATUS"));
// Toast.makeText( getApplicationContext(), "Payment Transaction response " + inResponse.toString(), Toast.LENGTH_LONG ).show();
}
#Override
public void networkNotAvailable() {
// If network is not
// available, then this
// method gets called.
}
#Override
public void clientAuthenticationFailed(String inErrorMessage) {
// This method gets called if client authentication
// failed. // Failure may be due to following reasons //
// 1. Server error or downtime. // 2. Server unable to
// generate checksum or checksum response is not in
// proper format. // 3. Server failed to authenticate
// that client. That is value of payt_STATUS is 2. //
// Error Message describes the reason for failure.
Utils.logD(TAG, "clientAuthenticationFailed " + inErrorMessage);
}
#Override
public void onErrorLoadingWebPage(int iniErrorCode,
String inErrorMessage, String inFailingUrl) {
Utils.logD(TAG, "inErrorMessage " + inErrorMessage);
Utils.logD(TAG, "inFailingUrl " + inFailingUrl);
}
// had to be added: NOTE
#Override
public void onBackPressedCancelTransaction() {
// TODO Auto-generated method stub
}
#Override
public void onTransactionCancel(String inErrorMessage, Bundle inResponse) {
Utils.logD(TAG, "Payment Transaction Failed " + inErrorMessage);
Toast.makeText(getBaseContext(), "Payment Transaction Failed ", Toast.LENGTH_LONG).show();
}
});
}
This is the Gradle dependency
implementation('com.paytm:pgplussdk:1.2.3') {
transitive = true
}
I have tried the Test environment and Production as well, but getting the checksum mismatch error every time.
For testing purposes, I have set the values hardcoded. I have gone various threads over the Paytm QA forum but they did not provide any sufficient answer to the threads(threads same as mine).
In PHP
Change this
$paytmParams["ORDER_ID"] = "order1";
to this
$paytmParams["ORDERID"] = "order1";
In APP
Change this
paramMap.put( "ORDER_ID" , "order1");
to this
paramMap.put( "ORDERID" , "order1");

Firebase push notification using PHP

I'm using Firebase for push notifications. My PHP code is working fine. I'm getting success message, but not receiving the push notification in my Android app for single device and multi device. But using Firebase console for sending notification it's working fine. I got the notification on the Android device. Is there any server configuration that I need to add?
PHP Code:
$yourApiSecret = "AIzaSyDY";
$androidAppId = "traasasadad";
$data = array(
"tokens" => "AAAA_kFbSQ4:APA91bQuMV-nRuTnVNFg0HD2C9PBnWWad",
"notification" => "Hello World!"
);
$data_string = json_encode($data);
$ch = curl_init('https://push.ionic.io/api/v1/push');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'X-Ionic-Application-Id: '.$androidAppId,
'Content-Length: ' . strlen($data_string),
'Authorization: Basic '.base64_encode($yourApiSecret)
)
);
$result = curl_exec($ch);
var_dump($result);
Android Code:
package com.seven77Trades.notification;
/** * Created by ist on 21/3/17. */ 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
com.seven77Trades.HomeActivity; import com.seven77Trades.R;
public class FirebaseMsgService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* Called when message is received.
*
* #param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
// [START receive_message]
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// [START_EXCLUDE]
// There are two types of messages data messages and notification messages. Data messages are handled
// here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
// traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
// is in the foreground. When the app is in the background an automatically generated notification is displayed.
// When the user taps on the notification they are returned to the app. Messages containing both notification
// and data payloads are treated as notification messages. The Firebase console always sends notification
// messages. For more see:
// [END_EXCLUDE]
// TODO(developer): Handle FCM messages here.
// Not getting messages here? See why this may be:
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
/*Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getColor());
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getSound());
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getTag());
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getClickAction());*/
sendNotification(remoteMessage.getNotification().getBody());
}
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
}
// [END receive_message]
/**
* Create and show a simple notification containing the received FCM message.
*
* #param messageBody FCM message body received.
*/
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* 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_logo)
.setContentTitle("Firebase")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
} }
Output:
"{"multicast_id":8295856130292351869,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1492611205996022%0296efeff9fd7ecd"}]}"
I got the solution .finally I'm receiving notification in android device.When we are sending notification using API (php,java,python) that time android application getting this request in different method (WakefulBroadcastReceiver) and when we sending using fire base console then request comes different method (FirebaseMessagingService).
Here the BrackPullBroadCastReceiver:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
public class GcmIntentService extends IntentService {
private Context context;
public GcmIntentService() {
super("GcmIntentService");
}
String imageUrl = "";
#Override
protected void onHandleIntent(Intent intent) {
context = this;
Bundle extras = intent.getExtras();
for (String key: extras.keySet())
{
Log.d (TAG, key + " is a key in the bundle");
Log.d(TAG, extras.get(key) + "");
}
}
}
I think there is some mistake with the target url you can try sending the notification like this:
$url = 'http://fcm.googleapis.com/fcm/send';
$fields =array(
"notification"=> array(
"title" => 'sometitle',
"body" => $message, //Can be any message you want to send
"icon" => $image,
"click_action" => "http://google.com"
),
"registration_ids"=> 'Your android app fcm token',
"data"=> array(
"data" => "something",
)
);
$fields = json_encode ( $fields );
$headers = array (
'Authorization: key=' . "your firebase app 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_POSTFIELDS, $fields );
$result = curl_exec ( $ch );
curl_close ( $ch );
Also you can pass custom data in the payload

Confusions about new GoogleCloudMessaging API (not the old one)

i have followed the tutorial for GCM available at the official site:
http://developer.android.com/google/gcm/gs.html
and i have successfully implemented it on my app.. but as i am new on android i have few confusions about GCM i would really appriciate if someone could clear these points.
i wrote a PHP script(found from google) and hardcoded my regisration ID (just for testing) when i run the script i recieve a notification on my device.. but i dont wanna receive a notification rather i want to silently recieve the data and handle it on my device. is it possible?? here is the PHP code:
$regID=$_REQUEST['regID'];
$registatoin_ids=array($regID);
$msg=array("message"=>'HI Wasif');
$url='https://android.googleapis.com/gcm/send';
$fields=array
(
'registration_ids'=>$registatoin_ids,
'data'=>$msg
);
$headers=array
(
'Authorization: key=MY-REG-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_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_POSTFIELDS,json_encode($fields));
$result=curl_exec($ch);
curl_close($ch);
echo $result;
Second point is i want to customize the notification i receive on my device i receive a notification like this...(see picture below) but i want to replace the heading text "GCM Notification" with my app's name and the message should me displayed properly(not like the key,value text) and also change the image of notification... can anybody plz provide a tutorial how to do it in new GoogleCloudMessaging API?? (please dont provide old methods if it is not same for new GoogleCouldMessaging API)
BROADCAST RECEIVER CODE:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Hope this link helps : GCM
1) If you don't want to receive notification on device then remove the code of Notification from GCMIntentService class under generateNotification() method.
2) You can provide your app name, app icon by implementing following code in generateNotification() method :
private static void generateNotification(Context context, String message) {
int icon = R.drawable.ic_launcher;
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
String title = context.getString(R.string.app_name);
Intent notificationIntent = new Intent(context, MainActivity.class);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent =
PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// Play default notification sound
notification.defaults |= Notification.DEFAULT_SOUND;
// Vibrate if vibrate is enabled
notification.defaults |= Notification.DEFAULT_VIBRATE;
notificationManager.notify(0, notification);
}
Hope this helps.

Google cloud messaging GCM - Push Notification not being sent (Server Side)

I am able to get the device id and save it to my database, and when something happens, I try to send the push notification but it does not get delivered to the phone. Here is what I do in my PHP:
$url = 'https://android.googleapis.com/gcm/send';
$device_ids = array( $device_id );
$headers = array('Authorization: key=' . 'my_api_key',
'Content-Type: application/json');
$t_data = array();
$t_data['message'] = 'Someone commented on your business.';
$t_json = array( 'registration_ids' => $device_ids , 'data' => $t_data );
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Authorization: key=my_id', 'Content-Type: application/json' ) );
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode( $t_json ) );
curl_setopt($ch, CURLOPT_URL, $url);
$result = curl_exec($ch);
if ($result === FALSE)
{
die('Curl failed: ' . curl_error($ch));
}
curl_close($ch);
and here is the result I get from the curl_exec call:
{"multicast_id":8714083978034301091,"success":1,"failure":0,"canonical_ids":0,"r‌​esults":[{"message_id":"0:1350807053347963%9aab4bd8f9fd7ecd"}]}
One thing I am wondering is whether I have to do something extra in the app like write my own Reciever class?
Thanks!
EDIT:
Here is my GCMIntentService class:
package com.problemio;
import static com.google.android.gcm.GCMConstants.ERROR_SERVICE_NOT_AVAILABLE;
import static com.google.android.gcm.GCMConstants.EXTRA_ERROR;
import static com.google.android.gcm.GCMConstants.EXTRA_REGISTRATION_ID;
import static com.google.android.gcm.GCMConstants.EXTRA_SPECIAL_MESSAGE;
import static com.google.android.gcm.GCMConstants.EXTRA_TOTAL_DELETED;
import static com.google.android.gcm.GCMConstants.EXTRA_UNREGISTERED;
import static com.google.android.gcm.GCMConstants.INTENT_FROM_GCM_LIBRARY_RETRY;
import static com.google.android.gcm.GCMConstants.INTENT_FROM_GCM_MESSAGE;
import static com.google.android.gcm.GCMConstants.INTENT_FROM_GCM_REGISTRATION_CALLBACK;
import static com.google.android.gcm.GCMConstants.VALUE_DELETED_MESSAGES;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import com.google.android.gcm.GCMBaseIntentService;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Toast;
import utils.GCMConstants;
public class GCMIntentService extends GCMBaseIntentService
{
public GCMIntentService()
{
super(ProblemioActivity.SENDER_ID);
}
#Override
protected void onRegistered(Context ctxt, String regId) {
Log.d(getClass().getSimpleName(), "onRegistered: " + regId);
Toast.makeText(this, regId, Toast.LENGTH_LONG).show();
}
#Override
protected void onUnregistered(Context ctxt, String regId) {
Log.d(getClass().getSimpleName(), "onUnregistered: " + regId);
}
#Override
protected void onMessage(Context ctxt, Intent message) {
Bundle extras=message.getExtras();
for (String key : extras.keySet()) {
Log.d(getClass().getSimpleName(),
String.format("onMessage: %s=%s", key,
extras.getString(key)));
}
}
#Override
protected void onError(Context ctxt, String errorMsg) {
Log.d(getClass().getSimpleName(), "onError: " + errorMsg);
}
#Override
protected boolean onRecoverableError(Context ctxt, String errorMsg) {
Log.d(getClass().getSimpleName(), "onRecoverableError: " + errorMsg);
return(true);
}
}
UPDATE:
Looking at LogCat, it turned out that the message is getting to the device. But the device is not displaying the push notification for some reason.
From the response it seems that the message is delivered. On Android you should have a GCMIntentService class that extends GCMBaseIntentService, to receive the message on the device. You should check the gcm-demo-client that comes in the SDK samples for a good approach on how to implement this on the app. There you only need set the SENDER_ID (your google proyect number) in the CommonUtilities class to receive messages from your server.
More info here.
To generate the notification on the GCMIntentService you can use:
//Issues a notification to inform the user that server has sent a message.
private static void generateNotification(Context context, String message, String title,) {
int icon = R.drawable.logo;
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(context, AnActivity.class);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Notification notification = new NotificationCompat.Builder(context)
.setContentTitle(title)
.setContentText(message)
.setContentIntent(intent)
.setSmallIcon(icon)
.setLights(Color.YELLOW, 1, 2)
.setAutoCancel(true)
.setSound(defaultSound)
.build();
notificationManager.notify(0, notification);
}
Have you also registered the receiver on the manifest? Under the application tag?
<!--
BroadcastReceiver that will receive intents from GCM
services and handle them to the custom IntentService.
The com.google.android.c2dm.permission.SEND permission is necessary
so only GCM services can send data messages for the app.
-->
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<!-- Receives the actual messages. -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<!-- Receives the registration id. -->
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.google.android.gcm.demo.app" />
</intent-filter>
</receiver>
<!--
Application-specific subclass of GCMBaseIntentService that will
handle received messages.
By default, it must be named .GCMIntentService, unless the
application uses a custom BroadcastReceiver that redefines its name.
-->
<service android:name=".GCMIntentService" />
You only need a collapseKey if you are planning to have your messages overwrite the previous message of that type. So if you are sending a message that the app needs to sync you can give it a collapse key so it will only send 1 sync message. The official docs describe how to use it.
While sending notification from GCM Server, which url to be used?
https://android.googleapis.com/gcm/send or
https://gcm-http.googleapis.com/gcm/send

Categories