InvalidRegistration error in Firebase Cloud Messaging for Android
I am developing an Android app that using Push Notification feature. I need to push from server. I use Firebase for it. This is my first time using Firebase. But when I push from server using PHP and CURL, it is giving me invalid registration error.
I get the Firebase token in Android like this
String token = FirebaseInstanceId.getInstance().getToken();
Then I save sent that token to server and saved in the database.
At server, I am pushing like this
class Pusher extends REST_Controller {
function __construct()
{
parent::__construct();
}
public function notification_get()
{
$rows = $this->db->get('device_registration')->result();
$tokens= array();
if(count($rows)>0)
{
foreach($rows as $row)
{
$tokens[] = $row->token;
}
}
$message = array("message"=>"FCM PUSH NOTIFICATION TESTING");
if(count($tokens)>0)
{
$result = $this->send_notification($tokens,$message);
if(!$result)
{
die("Unable to send");
}
else{
$this->response($result, REST_Controller::HTTP_OK);
}
}
}
function send_notification($tokens,$message)
{
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array(
'registration_ids'=>$tokens,
'data'=>$message
);
$headers = array(
'Authorization:key = AIzaSyApyfgXsNQ3dFTGWR6ns_9pttr694VDe5M',//Server key from firebase
'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)
{
return FALSE;
}
curl_close($ch);
return $result;
}
}
I am using CodeIgniter 3 framework for building Rest API. When I push accessing URL from browser, it returns JSON data with error as in the below screenshot.
As you can see it is giving InvalidRegistration error and message is not pushed to devices. What is wrong with my code?
Additional
This is my FirebaseMessagingService class that show notification in Android
public class FirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
showNotification(remoteMessage.getData().get("message"));
}
private void showNotification(String message)
{
Intent i = new Intent(this,MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,i,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this).setAutoCancel(true)
.setContentTitle("FCM Test")
.setContentText(message)
.setSmallIcon(R.drawable.info)
.setContentIntent(pendingIntent);
NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
manager.notify(0,builder.build());
}
}
Although I am not using codeigniter, I was encountering the InvalidRegistration
error while sending to an iOS
device, so I thought I would share my solution here.
I had to change registration_ids to to in PHP when sending a Notification message
to a single device token, and make sure the value of to was a string and not an array.
Change this:
'registration_ids'=>$tokens,
To this:
'to'=>$tokens[0],
Invalid Registration ID Check the formatting of the registration ID that you pass to the server. Make sure it matches the registration ID the phone receives in the com.google.firebase.INSTANCE_ID_EVENT intent and that you're not truncating it or adding additional characters. Happens when error code is InvalidRegistration.
Please check with both the side app side and your side that the exact same registration id is stored in the server which Application on mobile receives it in on onTokenRefresh
method. You should have received the exact same registration token as developer got in FirebaseInstanceId.getInstance().getToken()
As i got your comment and you've updated the code here is some change in your code it is from google doc it self...
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// TODO(developer): Handle FCM messages here.
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());
}
// 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.
}
Firebase has three message types:
Notification messages: Notification message works on background or foreground. When app is in background, Notification messages are delivered to the system tray. If the app is in the foreground, messages are handled by onMessageReceived() or didReceiveRemoteNotification callbacks. These are essentially what is referred to as Display messages.
Data messages: On Android platform, data message can work on background and foreground. The data message will be handled by onMessageReceived(). A platform specific note here would be: On Android, the data payload can be retrieved in the Intent used to launch your activity.
Messages with both notification and data payloads: When in the background, apps receive the notification payload in the notification tray, and only handle the data payload when the user taps on the notification. When in the foreground, your app receives a message object with both payloads available. Secondly, the click_action parameter is often used in notification payload and not in data payload. If used inside data payload, this parameter would be treated as custom key-value pair and therefore you would need to implement custom logic for it to work as intended.
For Java in Android Do not use FirebaseInstallation for generating token i don't know why but it does not return the valid token. every time I receive "InvalidRegistration" when try to POST through FCM REST API.
{
"multicast_id": 8303815118005358735,
"success": 0,
"failure": 1,
"canonical_ids": 0,
"results": [
{
"error": "InvalidRegistration"
}
]
}
Instead Use This:
if (firebaseUser != null) {
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(task -> {
if (!task.isSuccessful()) {
Log.d(TAG, "getInstanceId failed", task.getException());
return;
}
if (task.getResult() != null) updateToken(task.getResult().getToken());
});
}
private void updateToken(String refreshToken) {
DocumentReference documentReference;
Token token1 = new Token(refreshToken);//just a class with str field
Map<String, Object> tokenMAp = new HashMap<>();
tokenMAp.put("tokenKey", token1.getToken());
Log.d(TAG, "updateToken: " + token1.getToken());
String id = firebaseUser.getUid();
baseref=sp.getString(BASE_REF,DEFAULT);
documentReference= FirebaseFirestore.getInstance().document(baseref);
updateDocWithToken(documentReference,tokenMAp);
}
private void updateDocWithToken(DocumentReference documentReference, Map<String, Object> tokenMAp) {
documentReference.set(tokenMAp, SetOptions.merge());
}