可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am new to Firebase and I am running into errors such as mismatch sender id and Authentication Error with HTTP status 401 when my Java application tries to send a notification/message using the client's Firebase token. Note that using Firebase Console, I am able to send the message to the client.
For the client app, I did the following:
- Cloned Firebase
messaging
quickstart app from here -- https://github.com/firebase/quickstart-android/tree/master/messaging -- which is already setup with Firebase dependencies and such. Loaded the cloned app in Android Studio
.
- Using Firebase Console, created a new project called
My Notification Client
and added an app using com.google.firebase.quickstart.fcm
as the package name of the Android app.
- Downloaded
google-services.json
file for the Android app added to the newly created project and copied it to the messaging/app/
folder and sync'd with Grade files from within Android Studio
.
- Created an emulator and ran the app from within
Android Studio
. When the app got loaded in the emulator, clicked the Log Token
button to capture the client's Firebase token in the Android Monitor
tab in Android Studio
.
- Using Firebase Console, selected the newly created project
My Notification Client
, clicked the Notifications
link from the left pane, and sent a notification to the device by pasting the Firebase token captured in the previous step.
This worked great! The next step was to to use a separate simple Java application (which would eventually become a notification server) to send the notification to the client instead of using Firebase Console.
To accomplish this, I followed the steps outlined here -- https://firebase.google.com/docs/server/setup#prerequisites. Specifically, these are the steps that I performed:
- Created a new project called
My Notification Server
in Firebase Console.
- Using
Settings > Permissions
in Firebase Console, created a new service account and downloaded the serviceAccountCredentials.json
file.
- Created a new maven project in Eclipse and added the following dependencies in pom.xml:
<dependency>
<groupId>com.google.gcm</groupId>
<artifactId>gcm-server</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-server-sdk</artifactId>
<version>3.0.0</version>
</dependency>
Then, I extended com.google.android.gcm.sender.Sender
to create FCMSender
and override protected method getConnection(String url)
to use the new FCM endpoint as shown below:
class FCMSender extends Sender {
public FCMSender(String key) {
super(key);
}
@Override
protected HttpURLConnection getConnection(String url) throws IOException {
String fcmUrl = "https://fcm.googleapis.com/fcm/send";
return (HttpURLConnection) new URL(fcmUrl).openConnection();
}
}
The main()
method of my Java application looks like this:
public static void main(String[] args) {
// Obtain serverKey from Project Settings -> Cloud Messaging tab
// for "My Notification Client" project in Firebase Console.
String serverKey = <get_server_key_from_firebase_console>;
Thread t = new Thread() {
public void run(){
try {
Sender sender = new FCMSender(serverKey);
Message message = new Message.Builder()
.collapseKey("message")
.timeToLive(3)
.delayWhileIdle(true)
.addData("message", "Notification from Java application");
.build();
// Use the same token(or registration id) that was earlier
// used to send the message to the client directly from
// Firebase Console's Notification tab.
Result result = sender.send(message,
"APA91bFfIFjSCcSiJ111rbmkpnMkZY-Ej4RCpdBZFZN_mYgfHwFlx-M1UXS5FqDBcN8x1efrS2md8L9K_E9N21qB-PIHUqQwmF4p7Y3U-86nCGH7KNkZNjjz_P_qjcTR0TOrwXMh33vp",
1);
System.out.println("Result: " + result.toString());
} catch (Exception e) {
e.printStackTrace();
}
};
t.start;
try {
t.join();
}
catch (InterruptedException iex) {
iex.printStackTrace();
}
}
When I run the Java application, I get MismatchSenderId
error. I tried troubleshooting using curl
as shown below but got the same error:
$ skey=<obtained_from_project_settings_cloud_messaging_tab_in_firebase_console>
$ curl -X POST --header "Authorization: key=$skey" \
--Header "Content-Type: application/json" \
https://fcm.googleapis.com/fcm/send \
-d "{\"to\":\"APA91bFfIFjSCcSiJ111rbmkpnMkZY-Ej4RCpdBZFZN_mYgfHwFlx-M1UXS5FqDBcN8x1efrS2md8L9K_E9N21qB-PIHUqQwmF4p7Y3U-86nCGH7KNkZNjjz_P_qjcTR0TOrwXMh33vp\",\"data\":{\"message\":\"Yellow\"}}"
{"multicast_id":7391851081942579857,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"MismatchSenderId"}]}
Instead of using the Server Key
listed on Project Settings > Cloud Messaging
tab for My Notification Server
project in Firebase Console, I tried using the Project Number
but that caused InvalidRequestException: HTTP Status Code: 401
.
Firebase documentation of the error codes says this about MismatchSenderId
:
Mismatched Sender 200 + error:MismatchSenderId
A registration token is tied to a certain group of senders. When a client app registers for FCM, it must specify which senders are allowed to send messages. You should use one of those sender IDs when sending messages to the client app. If you switch to a different sender, the existing registration tokens won't work.
I could not figure out where/how in Firebase Console one can configure the Android app(which was aded to the My Notification Client
project) to be able to receive messages.
Any help on this, would be appreciated!
回答1:
I was running into the same issue. The problem was in the line:
String serverKey = <get_server_key_from_firebase_console>;
This value should come from the Android app project; in this case it would be "My Notification Client" and not "My Notification Server".
回答2:
I too have recently started using Firebase, with no prior experience in Google Cloud Messaging. AFAIK, there's no server side SDK for Firebase Cloud Messaging, currently.
To send notifications/messages from your App Server to your Mobile Client, you need to implement your own HTTP and/or XMPP methods. See https://firebase.google.com/docs/cloud-messaging/
My testing code, using HTTP:
public CompletableFuture<String> fcmTest1() {
// https://firebase.google.com/docs/cloud-messaging/http-server-ref
String host = "fcm.googleapis.com";
String requestURI = "/fcm/send";
String CLIENT_TOKEN = "ASK_YOUR_MOBILE_CLIENT_DEV"; // https://developers.google.com/instance-id/
CompletableFuture<String> fut = new CompletableFuture<>();
JsonObject body = new JsonObject();
// JsonArray registration_ids = new JsonArray();
// body.put("registration_ids", registration_ids);
body.put("to", CLIENT_TOKEN);
body.put("priority", "high");
// body.put("dry_run", true);
JsonObject notification = new JsonObject();
notification.put("body", "body string here");
notification.put("title", "title string here");
// notification.put("icon", "myicon");
JsonObject data = new JsonObject();
data.put("key1", "value1");
data.put("key2", "value2");
body.put("notification", notification);
body.put("data", data);
HttpClientRequest hcr = httpsClient.post(443, host, requestURI).handler(response -> {
response.bodyHandler(buffer -> {
logger.debug("FcmTest1 rcvd: {}, {}", response.statusCode(), buffer.toString());
if (response.statusCode() == 200) {
fut.complete(buffer.toString());
} else {
fut.completeExceptionally(new RuntimeException(buffer.toString()));
}
});
});
hcr.putHeader("Authorization", "key=" + Utils.FIREBASE_SERVER_KEY)
.putHeader("content-type", "application/json").end(body.encode());
return fut;
}
note: http client and json were provided by vertx (http://vertx.io/), but hopefully the code shows what's going on clear enough so you can use whatever you wish.
回答3:
I wrote an FCMHelper Class, that works fine and is simple to use.
See here https://github.com/MOSDEV82/fcmhelper
回答4:
I needed to send FCM notification from my java EE application and I found this very helpful. Might save someone some time.
...The github repo is a library interface for Firebase Cloud Messaging (FCM) API (NB// I am not the author). So I followed instructions in the readme: added the jar file as a dependency to my project and could just invoke the library methods with respective parameters.
e.g. Pushraven.setKey(my_key);
to set your server key and
Notification raven = new Notification();
raven.title("MyTitle")
.text("Hello World!")
.color("#ff0000")
.to(client_key);
to build a notification. The instructions from the repo are pretty much clear and helpful.
回答5:
On:
// Obtain serverKey from Project Settings -> Cloud Messaging tab
// for "My Notification Server" project in Firebase Console.
String serverKey = <get_server_key_from_firebase_console>;
You must obtain the key for your android app.
And thank you, I was struggling to build a service to send/receive notifications for the app. Saw your question, tried to get it right, and used to build mine. Hope this will help you :)
回答6:
I have just started with FireBase, but it looks like someone ( Brandon Gresham ) has already made a firebase Java API.
You can check the third party APIs for different languages here :
https://firebase.google.com/docs/database/rest/start
And here is the Java one:
https://github.com/bane73/firebase4j
Thanks a lot to Brandon for dedicating time to it!
回答7:
I had the exacly same problem, and even used your code as a test to check if there was something wrong with mine. It turns out that both of our codes were right. The problem is exacly as described on Firebase docs:
"Mismatched Sender 200 + error:MismatchSenderId A registration token is
tied to a certain group of senders. When a client app registers for FCM, it
must specify which senders are allowed to send messages. You should use one
of those sender IDs when sending messages to the client app. If you switch
to a different sender, the existing registration tokens won't work."
Problem is, that´s not that clear (at least wasn´t for me).
So here's what you need: On your Android application, you'll need to receive the Firebase key for the device . It is not the same you used to have for the Google Cloud Message, and hence there´s the problem.
Just create this class on your Android project:
public class NotificacaoRegistro extends FirebaseInstanceIdService {
static private String TAG = "NOTIFICACAOREGISTRO";
public NotificacaoRegistro(){
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
}
@Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
// TODO: Implement this method to send any registration to your app's servers.
}
}
Don't forget to make the necessary changes on your AndroidManifest
<service
android:name=".notificacoes.NotificacaoRegistro">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
If you just need the code (for debugging, for example) you can just call on your MainActivity, in your OnCreate method
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
But it´s better, ofc if you take care of that properly.
That way you'll get the correct key for that device. Then on your Java application code
Result result = sender.send(message,
<PUT THE VALUE OF THE REFRESHED TOKEN HERE>,
1);
and you are all set :)
Hope this helps, and sorry about the long delay :)
cheers
回答8:
Use this sending push notifications from java.
Spring Framework
Compared to other projects there are just 3 simple classes with minimal dependencies.
https://github.com/AndreiD/testingpushnotifications
Remember to replace the SERVER_API_KEY and the Client_Token.