MismatchSenderId with Web Push PHP CURL Firebase - php

I am getting the following error when trying to send a Push Notification using Google Firebase:
{"multicast_id":1559489545169770337,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"MismatchSenderId"}]}
Can anyone give any clues why please?
It is a new setup and not being imported from GMC.
manifest.json contains:
"gcm_sender_id": "1225****"
This matches "Project Settings" > "Cloud Messaging" > [Sender ID]
The code for registering the user is:
function urlBase64ToUint8Array(base64String) {
var padding = '='.repeat((4 - base64String.length % 4) % 4);
var base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
var rawData = window.atob(base64);
var outputArray = new Uint8Array(rawData.length);
for (var i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
function subscribePush() {
navigator.serviceWorker.ready.then(function(registration) {
if (!registration.pushManager) {
alert('Your browser doesn\'t support push notification.');
return false;
}
registration.pushManager.subscribe({
userVisibleOnly: true //Set user to see every notification
, applicationServerKey: urlBase64ToUint8Array('*******')
//The "PUBLIC KEY PAIR" under Web configuration. Have tried with and without urlBase64ToUint8Array()
})
.then(function (subscription) {
console.info('Push notification subscribed.');
console.log(subscription);
//saveSubscriptionID(subscription);
})
.catch(function (error) {
console.error('Push notification subscription error: ', error);
});
})
}
My code is registering the user and the response from Firebase is (including "REGISTRATION ID"):
Data {"endpoint":"https://fcm.googleapis.com/fcm/send/****:*****","expirationTime":null,"keys":{"p256dh":"****","auth":"****"}}
I am then using this PHP cURL:
$id = "****:*****"; // "REGISTRATION ID" from the response above. If this is wrong it throws an error ("InvalidRegistration"), so I know that this is correct.
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array (
'registration_ids' => array (
$id
),
'data' => array (
"message" => "Test"
)
);
$fields = json_encode ( $fields );
$headers = array (
'Authorization: key=' . "********", //This is the "Server key" above "Sender ID"
//This matches "Project Settings" > "Cloud Messaging" > [Server Key]
//If this is wrong it returns: INVALID_KEY error 401. So I know this is correct.
'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, $fields );
$result = curl_exec ( $ch );
echo $result;
curl_close ( $ch );

So I eventually figured this out. Instead of using the Subscription ID from the end of
https://fcm.googleapis.com/fcm/send/ABCDEF:KJHASKHDASDetc
I used the following code, and used the TOKEN instead and used that as the "registration_ids" in the CURL post
<script src="https://www.gstatic.com/firebasejs/8.2.6/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.2.6/firebase-messaging.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/8.2.6/firebase-analytics.js"></script>
<script>
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
var firebaseConfig = {
apiKey: "****",
authDomain: "****",
projectId: "****",
storageBucket: "****",
messagingSenderId: "****",
appId: "****",
measurementId: "****"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
const messaging = firebase.messaging();
messaging.requestPermission()
.then(function() {
console.log('Notification permission granted.');
return messaging.getToken()
})
.then(function(result) {
console.log("The token is: ", result);
})
.catch(function(err) {
console.log('Unable to get permission to notify.', err);
});
messaging.getToken({ vapidKey: '*****-*****' }).then((currentToken) => {
if (currentToken) {
// Send the token to your server and update the UI if necessary
// ...
console.log("currentToken: ", currentToken);
} else {
// Show permission request UI
console.log('No registration token available. Request permission to generate one.');
// ...
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
// ...
});

Related

Error Code 400: Invalid Value - Google Play IAP Verification Failure

I had working code in my server, that verified in-app purchases.
There are already 2 days, that my verification started give me a bad response.
{
"error": {
"errors": [
{
"domain": "global",
"reason": "invalid",
"message": "Invalid Value"
}
],
"code": 400,
"message": "Invalid Value"
}
}
Nothing changed on my side.
(P.S. I'm able to get an access token via refresh, so, I assume I have no problems with my credentials).
Here is the code, that worked OK before.
$product_sku = $_REQUEST['product_sku'];
$transaction_id = $_REQUEST['transaction_id'];
$transaction_time = $_REQUEST['transaction_time'];
$purchase_data = #$_REQUEST['purchase_data'];
$market = $_REQUEST['market'];
$verified = false;
$test_purchase = false;
if (isset($product_sku) && isset($transaction_id) && isset($transaction_time) && isset($market)) {
// If it's GOOGLE
if ($market == '2') {
// verifies if the IAB is correct
if (isset($purchase_data) && $purchase_data != "") {
// Getting necessary data for verification
$client_id = file_get_contents('google_play_developer_api_client_id');
$client_secret = file_get_contents('google_play_developer_api_client_secret');
$refresh_token = file_get_contents('google_play_developer_api_refresh_token');
$refresh_token_url = 'https://accounts.google.com/o/oauth2/token';
$verification_url = "https://www.googleapis.com/androidpublisher/v3/applications/mypackage/purchases/products/" . $product_sku . "/tokens/" . $purchase_data;
// Preparing for the REFRESH_TOKEN request. This need to be changed after Memcache enabling.
// Will be needed to store the ACCESS_TOKEN in the Memcache for the expiration time and after expiring get new ACCESS_TOKEN with REFRESH_TOKEN
// constructing the necessary data for Google authentication
$data_array = array(
"grant_type" => "refresh_token",
"client_id" => $client_id,
"client_secret" => $client_secret,
"refresh_token" => $refresh_token
);
// replacing '\/' with '/' as after json_encode() the '/' in the array values will be replaced with '\/'
$data_array = str_replace("\/", "/", json_encode($data_array));
// contracting Headers for the REFRESH_TOKEN request
$headers = array(
'APIKEY: 111111111111111111111',
'Content-Type: application/json'
);
// making REFRESH_TOKEN request and getting the new ACCESS_TOKEN
$make_call = callAPI('POST', $refresh_token_url, $data_array, $headers);
$response = json_decode($make_call, true);
if (array_key_exists("access_token", $response)) {
$accessToken = $response["access_token"];
// preparing for the Verification request
// adding necessary headers
array_push($headers, "Authorization: OAuth " . $accessToken, "Accept: application/json");
// making Verification request and getting the receipt from Google
$make_call = callAPI('GET', $verification_url, false, $headers);
$receipt = json_decode($make_call, true);
if (array_key_exists("purchaseState", $receipt)) {
// checking for the test purchase or for the purchase made using promo code.
// if purchaseType exists in the receipt the it is test purchase or the purchase made using promo code
// purchaseType = 0 -> Test Purchase, purchaseType = 1 -> Purchase made using promo code
if (array_key_exists("purchaseType", $receipt)) {
$purchaseType = $receipt["purchaseType"];
$test_purchase = $purchaseType == 0;
}
// Getting the purchaseState from the receipt.
// purchaseState = 0 -> Successfull purchase, purchaseState = 0 -> Canceled purchase
$purchaseState = $receipt["purchaseState"];
// Getting Order Id from the receipt
$order_id = $receipt["orderId"];
// Getting Purchase Time from the receipt. Time in millis from the Unix Epoch
$purchaseTimeMillis = $receipt["purchaseTimeMillis"];
// Verifying the purchase
// Verification is failed for any of the following reasons
// 1. Test purchase or the purchase made using promo code
// 2. Canceled Purchase
// 3. If the order id from receipt and the transaction id from the mobile app are different
// 4. If the PurchaseTime from the receipt and the Transaction Time from the mobile are different
// If all conditions are true, the purchase is verified.
$verified = ($purchaseState == 0 && $order_id == $transaction_id && $purchaseTimeMillis == $transaction_time);
} elseif(!array_key_exists("error", $receipt)){
// Something went wrong, let's set the verified to true, so we don't know if it is cheating
$verified = true;
}
} else {
// Something went wrong, let's set the verified to true, so we don't know if it is cheat
$verified = true;
}
}
} else {
// Changed this, while adding verification for other platforms
$verified = true;
}
$verified = $verified ? 1 : 0;
$test_purchase = $test_purchase ? 1 : 0;
// Updating verified and test Purchase fields in the payment_transaction table
// The default value is 1, so no need for updating , if the payment is verified
if ($verified == 0 || $test_purchase == 1) {
dbQuery("UPDATE payment_transaction SET verified=$verified, test_purchase=$test_purchase WHERE user_id=$user_id AND txnid='$transaction_id'", $user_id);
}
$output['status'] = 'ok';
$output['verified'] = $verified;
$output['test_purchase'] = $test_purchase;
}
echo json_encode($output);
function callAPI($method, $url, $data = false, $headers = null)
{
$curl = curl_init();
switch ($method) {
case "POST":
curl_setopt($curl, CURLOPT_POST, 1);
if ($data)
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
break;
case "GET":
if ($data)
$url = sprintf("%s?%s", $url, http_build_query($data));
}
// OPTIONS:
curl_setopt($curl, CURLOPT_URL, $url);
if ($headers) {
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
// EXECUTE:
$result = curl_exec($curl);
if (! $result) {
die("Connection Failure");
}
curl_close($curl);
return $result;
}
?>
Any Ideas what may be the reason for the bad response?
I have tried to generate a new refresh token, but the result is the same. (
Ok. I found the problem. The PurchaseToken was incorrect in my case.
BTW, the Error Code 400 means that the authentication is ok , but some data is invalid. In my case, it was the PurchaseToken.

Send fcm push notification with iOS and PHP

I'm trying to write an application to receive notifications via Firebase Cloud Messaging. It initially worked when I tried to send the message via the Firebase console, but then the moment I tried doing the same using PHP webservice, in response, it showed success, but I neither received the message nor am I able to get any more notifications via Firebase console. How can I fix this?
My code in the server side:
<?php
function send_notification ($tokens, $message)
{
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'registration_ids' => $tokens,
'data' => $message
);
$headers = array(
'Authorization:key = AIzaSyDjrLKZGs4OcIgBPxpFnTzGeZHur4v9V8U',
'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;
}
$conn = mysqli_connect("localhost:3306", "minaaaa", "tt#2018", "dbSurvey");
$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);
$message = array("message" => " FCM PUSH NOTIFICATION TEST MESSAGE");
$message_status = send_notification($tokens, $message);
echo $message_status;
?>
Code in Swift:
UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, MessagingDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
Util.copyFile(fileName: "db.zanjanwireFinal01.db")
//let alert = UIAlertController(title: title, message: message , preferredStyle: .alert)
UNUserNotificationCenter.current().requestAuthorization(options: [.alert,.sound,.badge]){(isGranted, err)
in
if err != nil {
}
else
{
UNUserNotificationCenter.current().delegate = self
Messaging.messaging().delegate = self
if let token = InstanceID.instanceID().token() {
print("DCS: " + token)
self.RegisterUsers(testStr: token)
}
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
FirebaseApp.configure()
return true
}
func ConnectToFCM() {
Messaging.messaging().shouldEstablishDirectChannel = true
if let token = InstanceID.instanceID().token() {
print("DCS: " + token)
RegisterUsers(testStr: token)
}
}
func RegisterUsers(testStr:String){
let request = NSMutableURLRequest(url: NSURL(string:
request.httpMethod = "POST"
var dataString = "Token=\(testStr)"
print (dataString)
request.httpBody = dataString.data(using: String.Encoding.utf8)
let task = URLSession.shared.dataTask(with: request as URLRequest){
data, response, error in
if error != nil {
print("fffffffffatemeeeeeee")
print("error=\(error)")
return
}
print("response = \(response)")
let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
print("responseString = \(responseString)")
}
task.resume()
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to
// inactive state. This can occur for certain types of
// temporary interruptions (such as an incoming phone call
// or SMS message) or when the user quits the application
// and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers,
// and invalidate graphics rendering callbacks. Games
// should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user
// data, invalidate timers, and store enough application
// state information to restore your application to its
// current state in case it is terminated later.
// If your application supports background execution, this
// method is called instead of applicationWillTerminate:
// when the user quits.
//FirstMenueViewController().update()
Messaging.messaging().shouldEstablishDirectChannel = false
}
func applicationWillEnterForeground(_ application: UIApplication) {
FirstMenueViewController().update()
// Called as part of the transition from the background
// to the active state; here you can undo many of the
// changes made on entering the background.
ConnectToFCM()
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started)
// while the application was inactive. If the application
// was previously in the background, optionally refresh
// the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate.
// Save data if appropriate. See also
// applicationDidEnterBackground:.
}
func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
ConnectToFCM()
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
UIApplication.shared.applicationIconBadgeNumber += 1
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "com.DouglasDevlops.BadgeWasUpdated"), object: nil)
}
Structure your notification payload like this,

How come my request to send Firebase notification to a topic is not working (HTTP POST)?

Extremely grateful for any help with this.. all I want to do is use my php code to send notifications to all users subscribed to topic "global". Does anyone know why it might not work? Since I want everyone using the app to get the notifications, I will subscribe everyone (unless there is a better way). Here is my php to try to send the notification to my topic global:
<?php
define( 'API_ACCESS_KEY', 'hidden...hidden' );
$msg = array
(
'message' => 'here is a message. message',
'title' => 'This is a title. title',
'vibrate' => 1,
'sound' => 1
);
$fields = array
(
'to' => "/topics/global",
'data' => $msg,
'priority' => 'high'
);
$headers = array
(
'Authorization: key=' . API_ACCESS_KEY,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt( $ch,CURLOPT_URL, 'https://android.googleapis.com/gcm/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 am lacking knowledge but from the $result echo it didn't look like any failure message. This is what I got:
{"message_id":7591682951632927615}
In my Firebase console, I cannot even see the topic "global" so I can't test that sending to the topic works on my device. From what I read online, it could take awhile for a subscribed topic to appear in the console. Just to clarify, sending notifications to all devices using user segment set to the App works in the console!
Is there anything that I can do to verify that my app is actually subscribing users to the topic "global"? Maybe this is the problem. Here is the relevant swift code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FIRApp.configure()
if #available(iOS 10.0, *) {
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
// For iOS 10 data message (sent via FCM)
FIRMessaging.messaging().remoteMessageDelegate = self
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()
return true
}
func applicationReceivedRemoteMessage(_ remoteMessage: FIRMessagingRemoteMessage) {
print("applicationReceivedRemoteMessage")
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
if let refreshedToken = FIRInstanceID.instanceID().token() {
print("InstanceID token: \(refreshedToken)")
FIRMessaging.messaging().subscribe(toTopic: "/topics/global")
}
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
/*
// Print message ID.
if let messageID = userInfo["gcmMessageIDKey"] {
print("Message ID: \(messageID)")
}
// Print full message.
print(userInfo)
*/
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
if application.applicationState == UIApplicationState.active {
print("GOT IN HERE")
var pushNotificationMessage = ""
if let aps = userInfo["aps"] as? NSDictionary {
if let alert = aps["alert"] as? NSDictionary {
if let message = alert["message"] as? NSString {
pushNotificationMessage = message as String
}
} else if let alert = aps["alert"] as? NSString {
pushNotificationMessage = alert as String
}
}
let notificationAlert = UIAlertController(title: nil, message: pushNotificationMessage, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: {
(alert: UIAlertAction!) -> Void in
})
defaultAction.setValue(Constants.activePushNotificationOKColor, forKey: "titleTextColor")
notificationAlert.addAction(defaultAction)
self.window?.rootViewController?.present(notificationAlert, animated: true, completion: nil)
}
}
To send a notification, store the parameters in notification, not data:
$fields = array
(
'to' => "/topics/global",
'notification' => $msg, // <= CHANGED
'priority' => 'high'
);
Also look at Table 2a in the documentation for Notification payload support. message is not supported, use body instead.
$msg = array
(
'body' => 'here is a message. message', // <= CHANGED
'title' => 'This is a title. title',
'vibrate' => 1,
'sound' => 1
);

FCM give success but Notification is not received by device in Ionic V1

I am using FIREBASE CLOUD MESSAGING service with my ionic product and phonegap-plugin-push cordova plugin to get push notification from PHP BACK END.
When I am trying to get push notification then php end is getting result with success as below.
Sample Push Data Payload
{"multicast_id":8853634389214913500,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1495614850271706%39688dd8f9fd7ecd"}]}
Technology specification :
cordova push notification plugin version :1.9.4
Platform and Version: Ionic V1
Ionic CLI version : 2.1.13
Cordova version : cordova --6.4.0
Android platform for cordova :6.0.0
Android) What device vendor I have tested : Samsung, HUWAWEI, Xiaomi
etc.
Sample Code that illustrates the problem as below
IONIC PART:
//Push Notification
if (window.cordova) {
if (!localStorage.getItem('device_token')) {
var apkId = 0;
var iosId = 0;
var options = {
android: {
senderID: MY FCM SENDER ID,
icon: "alert",
},
ios: {
alert: "true",
badge: "true",
sound: "true"
},
windows: {}
};
//localStorage.getItem('gcmRegId')
// initialize
$cordovaPushV5.initialize(options).then(function () {
// start listening for new notifications
$cordovaPushV5.onNotification();
// start listening for errors
$cordovaPushV5.onError();
// register to get registrationId
$cordovaPushV5.register().then(function (data) {
//alert("GCM"+data);
// if Android device.
if (ionic.Platform.isAndroid()) {
apkId = data;
}
// if ios device.
if (ionic.Platform.isIOS()) {
iosId = data;
}
// Updating member details with apkId or iosId
var pushParams = {
'app_token': Config.appToken,
'device_uiu_token': device.uuid,
'apk_token': apkId,
'ios_token': iosId
}
$http.post(Config.apiUrl + "member/save_token", pushParams)
.success(function (data) {
if (data.status == 200) {
localStorage.setItem("device_token", device.uuid);
}
/* else{
alert("Sorry!Error occurs!");
} */
});
})
// Updating end.
});
// triggered every time notification received
$rootScope.$on('$cordovaPushV5:notificationReceived', function (event, data) {
alert("recieved" + JSON.stringify(data));
// data.message,
// data.title,
// data.count,
// data.sound,
// data.image,
// data.additionalData
});
// triggered every time error occurs
$rootScope.$on('$cordovaPushV5:errorOcurred', function (event, e) {
alert('push ERROR' + e.message);
// e.message
});
// push notification end
PHP PART:
$push_title = $this->input->post('push_title');
$push_msg = $this->input->post('push_msg');
$members = $this->members_model->get_members();
$apk_tokens = array();
$ios_tokens = array();
foreach ($members as $member) {
if ($member['apk_token'] != 0 || $member['apk_token'] != "") {
array_push($apk_tokens, $member['apk_token']);
}
if ($member['ios_token'] != 0 || $member['ios_token'] != "") {
array_push($ios_tokens, $member['ios_token']);
}
}
//Sending the push notification using GCM.
$msg = array(
'message' => $push_msg,
'title' => $push_title,
'vibrate' => 1,
'sound' => 1,
'largeIcon' => 'large_icon',
'smallIcon' => 'small_icon',
);
$fields = array
(
'registration_ids' => $apk_tokens,
'data' => $msg,
'priority' => 'high'
);
$headers = array
(
'Authorization: MY FCM SERVER 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;
Thanks in advance!
If you want to show the notification on lock screen, use notification in $fields. The object requires title and body elements.
https://firebase.google.com/docs/cloud-messaging/server#implementing-http-connection-server-protocol
$fields = array
(
'registration_ids' => $apk_tokens,
'data' => $msg,
'priority' => 'high',
'notification' => array(
'title' => 'This is title',
'body' => 'This is body'
)
);
I did not try this code, but same issue with node.js SDK has been fixed in this way.

GCM Notifications not receiving when app is in background mode in iOS

I have configured GCM in my existing app and i am receiving the notifications there. Now i am facing two problem:
1) I am not receiving notifications When i exit the application or application is in the background.
2) I am not receiving notification in iphone's notification area, only when my app is running i only direct receive alert message there. And when i pull down notification area i get this message in xcode's console "Could not connect to GCM: The operation couldn’t be completed. (com.google.gcm error 2001.)"
My PHP file is below
<?php
// Payload data you want to send to iOSdevice(s)
// (it will be accessible via intent extras)
$data = array( 'message' => 'Hello World!');
// The recipient registration tokens for this notification
// http://developer.android.com/google/gcm/
$ids = array( 'kucy6xoUmx********eeRsla' );
// Send a GCM push
sendGoogleCloudMessage( $data, $ids );
function sendGoogleCloudMessage( $data, $ids )
{
// Insert real GCM API key from Google APIs Console
// https://code.google.com/apis/console/
$apiKey = 'AIz******9JA';
// Define URL to GCM endpoint
$url = 'https://gcm-http.googleapis.com/gcm/send';
// Set GCM post variables (device IDs and push payload)
$post = array(
'registration_ids' => $ids,
'data' => $data,
);
// Set CURL request headers (authentication and type)
$headers = array(
'Authorization: key=' . $apiKey,
'Content-Type: application/json'
);
// Initialize curl handle
$ch = curl_init();
// Set URL to GCM endpoint
curl_setopt( $ch, CURLOPT_URL, $url );
// Set request method to POST
curl_setopt( $ch, CURLOPT_POST, true );
// Set our custom headers
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
// Get the response back as string instead of printing it
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
// Set JSON post data
curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode( $post ) );
// Actually send the push
$result = curl_exec( $ch );
// Error handling
if ( curl_errno( $ch ) )
{
echo 'GCM error: ' . curl_error( $ch );
}
// Close curl handle
curl_close( $ch );
// Debug GCM response
echo $result;
}
?>
Here is my AppDelegate.m file
// [START register_for_remote_notifications]
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// [START_EXCLUDE]
_registrationKey = #"onRegistrationCompleted";
_messageKey = #"onMessageReceived";
// Configure the Google context: parses the GoogleService-Info.plist, and initializes
// the services that have entries in the file
NSError* configureError;
[[GGLContext sharedInstance] configureWithError:&configureError];
NSAssert(!configureError, #"Error configuring Google services: %#", configureError);
_gcmSenderID = [[[GGLContext sharedInstance] configuration] gcmSenderID];
// Register for remote notifications
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1) {
// iOS 7.1 or earlier
UIRemoteNotificationType allNotificationTypes =
(UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge);
[application registerForRemoteNotificationTypes:allNotificationTypes];
} else {
// iOS 8 or later
// [END_EXCLUDE]
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
// [END register_for_remote_notifications]
// [START start_gcm_service]
GCMConfig *gcmConfig = [GCMConfig defaultConfig];
gcmConfig.receiverDelegate = self;
[[GCMService sharedInstance] startWithConfig:gcmConfig];
// [END start_gcm_service]
__weak typeof(self) weakSelf = self;
// Handler for registration token request
_registrationHandler = ^(NSString *registrationToken, NSError *error){
if (registrationToken != nil) {
weakSelf.registrationToken = registrationToken;
NSLog(#"Registration Token: %#", registrationToken);
[weakSelf subscribeToTopic];
NSDictionary *userInfo = #{#"registrationToken":registrationToken};
[[NSNotificationCenter defaultCenter] postNotificationName:weakSelf.registrationKey
object:nil
userInfo:userInfo];
} else {
NSLog(#"Registration to GCM failed with error: %#", error.localizedDescription);
NSDictionary *userInfo = #{#"error":error.localizedDescription};
[[NSNotificationCenter defaultCenter] postNotificationName:weakSelf.registrationKey
object:nil
userInfo:userInfo];
}
};
return YES;
}
- (void)subscribeToTopic {
// If the app has a registration token and is connected to GCM, proceed to subscribe to the
// topic
if (_registrationToken && _connectedToGCM) {
[[GCMPubSub sharedInstance] subscribeWithToken:_registrationToken
topic:SubscriptionTopic
options:nil
handler:^(NSError *error) {
if (error) {
// Treat the "already subscribed" error more gently
if (error.code == 3001) {
NSLog(#"Already subscribed to %#",
SubscriptionTopic);
} else {
NSLog(#"Subscription failed: %#",
error.localizedDescription);
}
} else {
self.subscribedToTopic = true;
NSLog(#"Subscribed to %#", SubscriptionTopic);
}
}];
}
}
// [START connect_gcm_service]
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Connect to the GCM server to receive non-APNS notifications
[[GCMService sharedInstance] connectWithHandler:^(NSError *error) {
if (error) {
NSLog(#"Could not connect to GCM: %#", error.localizedDescription);
} else {
_connectedToGCM = true;
NSLog(#"Connected to GCM");
// [START_EXCLUDE]
[self subscribeToTopic];
// [END_EXCLUDE]
}
}];
}
// [END connect_gcm_service]
// [START disconnect_gcm_service]
- (void)applicationDidEnterBackground:(UIApplication *)application {
[[GCMService sharedInstance] disconnect];
// [START_EXCLUDE]
_connectedToGCM = NO;
// [END_EXCLUDE]
}
// [END disconnect_gcm_service]
// [START receive_apns_token]
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// [END receive_apns_token]
// [START get_gcm_reg_token]
// Create a config and set a delegate that implements the GGLInstaceIDDelegate protocol.
GGLInstanceIDConfig *instanceIDConfig = [GGLInstanceIDConfig defaultConfig];
instanceIDConfig.delegate = self;
// Start the GGLInstanceID shared instance with the that config and request a registration
// token to enable reception of notifications
[[GGLInstanceID sharedInstance] startWithConfig:instanceIDConfig];
_registrationOptions = #{kGGLInstanceIDRegisterAPNSOption:deviceToken,
kGGLInstanceIDAPNSServerTypeSandboxOption:#"NO"};
[[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:_gcmSenderID
scope:kGGLInstanceIDScopeGCM
options:_registrationOptions
handler:_registrationHandler];
// [END get_gcm_reg_token]
}
// [START receive_apns_token_error]
- (void)application:(UIApplication *)application
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(#"Registration for remote notification failed with error: %#", error.localizedDescription);
// [END receive_apns_token_error]
NSDictionary *userInfo = #{#"error" :error.localizedDescription};
[[NSNotificationCenter defaultCenter] postNotificationName:_registrationKey
object:nil
userInfo:userInfo];
}
// [START ack_message_reception]
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
NSLog(#"Notification received: %#", userInfo);
// This works only if the app started the GCM service
[[GCMService sharedInstance] appDidReceiveMessage:userInfo];
// Handle the received message
// [START_EXCLUDE]
[[NSNotificationCenter defaultCenter] postNotificationName:_messageKey
object:nil
userInfo:userInfo];
// [END_EXCLUDE]
}
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))handler {
NSLog(#"Notification received: %#", userInfo);
// This works only if the app started the GCM service
[[GCMService sharedInstance] appDidReceiveMessage:userInfo];
// Handle the received message
// Invoke the completion handler passing the appropriate UIBackgroundFetchResult value
// [START_EXCLUDE]
[[NSNotificationCenter defaultCenter] postNotificationName:_messageKey
object:nil
userInfo:userInfo];
handler(UIBackgroundFetchResultNoData);
// [END_EXCLUDE]
}
// [END ack_message_reception]
// [START on_token_refresh]
- (void)onTokenRefresh {
// A rotation of the registration tokens is happening, so the app needs to request a new token.
NSLog(#"The GCM registration token needs to be changed.");
[[GGLInstanceID sharedInstance] tokenWithAuthorizedEntity:_gcmSenderID
scope:kGGLInstanceIDScopeGCM
options:_registrationOptions
handler:_registrationHandler];
}
// [END on_token_refresh]
// [START upstream_callbacks]
- (void)willSendDataMessageWithID:(NSString *)messageID error:(NSError *)error {
if (error) {
// Failed to send the message.
} else {
// Will send message, you can save the messageID to track the message
}
}
- (void)didSendDataMessageWithID:(NSString *)messageID {
// Did successfully send message identified by messageID
}
// [END upstream_callbacks]
- (void)didDeleteMessagesOnServer {
// Some messages sent to this device were deleted on the GCM server before reception, likely
// because the TTL expired. The client should notify the app server of this, so that the app
// server can resend those messages.
}
I am not a php script master so please help me that how i can resolve my issues.
I have added
'content_available' => true,//to trigger when iOS app is in background
'priority' => 'high',
'notification' => $data,
$data = array( 'message' => 'Hello World!', 'body' => 'Hello World!');
to your code.
Please try below code;
<?php
// Payload data you want to send to iOSdevice(s)
// (it will be accessible via intent extras)
$data = array( 'message' => 'Hello World!', 'body' => 'Hello World!');
// The recipient registration tokens for this notification
// http://developer.android.com/google/gcm/
$ids = array( 'kucy6xoUmx********eeRsla' );
// Send a GCM push
sendGoogleCloudMessage( $data, $ids );
function sendGoogleCloudMessage( $data, $ids )
{
// Insert real GCM API key from Google APIs Console
// https://code.google.com/apis/console/
$apiKey = 'AIz******9JA';
// Define URL to GCM endpoint
$url = 'https://gcm-http.googleapis.com/gcm/send';
// Set GCM post variables (device IDs and push payload)
$post = array(
'registration_ids' => $ids,
'data' => $data,
'content_available' => true,
'priority' => 'high',
'notification' => $data,
);
// Set CURL request headers (authentication and type)
$headers = array(
'Authorization: key=' . $apiKey,
'Content-Type: application/json'
);
// Initialize curl handle
$ch = curl_init();
// Set URL to GCM endpoint
curl_setopt( $ch, CURLOPT_URL, $url );
// Set request method to POST
curl_setopt( $ch, CURLOPT_POST, true );
// Set our custom headers
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
// Get the response back as string instead of printing it
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
// Set JSON post data
curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode( $post ) );
// Actually send the push
$result = curl_exec( $ch );
// Error handling
if ( curl_errno( $ch ) )
{
echo 'GCM error: ' . curl_error( $ch );
}
// Close curl handle
curl_close( $ch );
// Debug GCM response
echo $result;
}
?>
on IOS side;
Follow orders on GCM Site
EDIT 1:
You may try sending notification for ios;
I edited your php code above;
Changes are;
'notification' => $data,
and
$data = array( 'message' => 'Hello World!', 'body' => 'Hello World!');
GCM receiving notification in invalid state 2.
Developers who are using GCM integration for both Android and iOS need to add specific things in their Post call to the GCM Server.
For iOS:
We need two additional things to make the same call work in iOS:
'notification' => $data,
'content_available'=> 'true',
The Apple push notifications service requires content_available is true. And then 'notification'=> $data helps the Notification center to know that the notification has arrived and needs to be pushed to the device.

Categories