搜索文档后,我找不到任何有关如何在不使用外部服务器的情况下使用 FCM 向设备发送消息的信息。
例如,如果我正在创建一个聊天应用程序,我需要向用户发送有关未读消息的推送通知,因为他们不会一直在线,而且我无法在后台拥有始终连接到的持久服务实时数据库,因为那样会占用大量资源。
那么当某个用户“B”向他/她发送聊天消息时,我将如何向用户“A”发送推送通知?我需要一个外部服务器吗?还是可以只使用 Firebase 服务器来完成?
搜索文档后,我找不到任何有关如何在不使用外部服务器的情况下使用 FCM 向设备发送消息的信息。
例如,如果我正在创建一个聊天应用程序,我需要向用户发送有关未读消息的推送通知,因为他们不会一直在线,而且我无法在后台拥有始终连接到的持久服务实时数据库,因为那样会占用大量资源。
那么当某个用户“B”向他/她发送聊天消息时,我将如何向用户“A”发送推送通知?我需要一个外部服务器吗?还是可以只使用 Firebase 服务器来完成?
更新:现在可以使用 firebase 云功能作为处理推送通知的服务器。在此处查看他们的文档
=============
根据文档,您必须实现一个服务器来处理设备到设备通信中的推送通知。
在您可以编写使用 Firebase 云消息传递的客户端应用之前,您必须拥有一个满足以下条件的应用服务器:
...
您需要决定要使用哪个 FCM 连接服务器协议来使您的应用服务器能够与 FCM 连接服务器进行交互。请注意,如果要使用来自客户端应用程序的上游消息传递,则必须使用 XMPP。有关这方面的更详细讨论,请参阅选择 FCM 连接服务器协议。
如果您只需要从服务器向您的用户发送基本通知。您可以使用他们的无服务器解决方案Firebase Notifications。
在此处查看 FCM 和 Firebase 通知之间的比较: https ://firebase.google.com/support/faq/#messaging-difference
使用带有所需标头和数据的链接https://fcm.googleapis.com/fcm/send发出 HTTP POST 请求对我有帮助。在下面的代码片段
Constants.LEGACY_SERVER_KEY
中是一个本地类变量,您可以在 Firebase Project 中找到它Settings->Cloud Messaging->Legacy Server key
。您需要传递设备注册令牌,即regToken
在下面引用的代码片段中。
最后,您需要okhttp库依赖项才能使此代码段正常工作。
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
private void sendNotification(final String regToken) {
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
try {
OkHttpClient client = new OkHttpClient();
JSONObject json=new JSONObject();
JSONObject dataJson=new JSONObject();
dataJson.put("body","Hi this is sent from device to device");
dataJson.put("title","dummy title");
json.put("notification",dataJson);
json.put("to",regToken);
RequestBody body = RequestBody.create(JSON, json.toString());
Request request = new Request.Builder()
.header("Authorization","key="+Constants.LEGACY_SERVER_KEY)
.url("https://fcm.googleapis.com/fcm/send")
.post(body)
.build();
Response response = client.newCall(request).execute();
String finalResponse = response.body().string();
}catch (Exception e){
//Log.d(TAG,e+"");
}
return null;
}
}.execute();
}
进一步,如果您想向特定主题发送消息,请regToken
像这样在 json中替换
json.put("to","/topics/foo-bar")
并且不要忘记在您的 AndroidManifest.xml 中添加 INTERNET 权限。
重要: - 使用上面的代码意味着您的服务器密钥驻留在客户端应用程序中。这很危险,因为有人可以深入您的应用程序并获取服务器密钥以向您的用户发送恶意通知。
您可以使用 Volly Jsonobject 请求来做到这一点......
首先按照以下步骤操作:
1复制旧服务器密钥并将其存储为Legacy_SERVER_KEY
旧版服务器密钥
你可以在图片中看到如何获得
2你需要 Volley 依赖
编译'com.mcxiaoke.volley:library:1.0.19'
发送推送代码:-
private void sendFCMPush() {
String Legacy_SERVER_KEY = YOUR_Legacy_SERVER_KEY;
String msg = "this is test message,.,,.,.";
String title = "my title";
String token = FCM_RECEIVER_TOKEN;
JSONObject obj = null;
JSONObject objData = null;
JSONObject dataobjData = null;
try {
obj = new JSONObject();
objData = new JSONObject();
objData.put("body", msg);
objData.put("title", title);
objData.put("sound", "default");
objData.put("icon", "icon_name"); // icon_name image must be there in drawable
objData.put("tag", token);
objData.put("priority", "high");
dataobjData = new JSONObject();
dataobjData.put("text", msg);
dataobjData.put("title", title);
obj.put("to", token);
//obj.put("priority", "high");
obj.put("notification", objData);
obj.put("data", dataobjData);
Log.e("!_@rj@_@@_PASS:>", obj.toString());
} catch (JSONException e) {
e.printStackTrace();
}
JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.POST, Constants.FCM_PUSH_URL, obj,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.e("!_@@_SUCESS", response + "");
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("!_@@_Errors--", error + "");
}
}) {
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Authorization", "key=" + Legacy_SERVER_KEY);
params.put("Content-Type", "application/json");
return params;
}
};
RequestQueue requestQueue = Volley.newRequestQueue(this);
int socketTimeout = 1000 * 60;// 60 seconds
RetryPolicy policy = new DefaultRetryPolicy(socketTimeout, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
jsObjRequest.setRetryPolicy(policy);
requestQueue.add(jsObjRequest);
}
只需调用sendFCMPush();
是的,可以在没有任何服务器的情况下执行此操作。您可以创建设备组客户端,然后在组中交换消息。但是有一些限制:
参考:Firebase doc请参阅“在 Android 客户端应用程序上管理设备组”部分
Google Cloud Functions 现在可以在没有应用服务器的情况下从设备到设备发送推送通知。我制作了云功能,当新消息添加到数据库中时触发
这是node.js
代码
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin'); admin.initializeApp();
exports.sendNotification = functions.database.ref('/conversations/{chatLocation}/{messageLocation}')
.onCreate((snapshot, context) => {
// Grab the current value of what was written to the Realtime Database.
const original = snapshot.val();
const toIDUser = original.toID;
const isGroupChat = original.isGroupChat;
if (isGroupChat) {
const tokenss = admin.database().ref(`/users/${toIDUser}/tokens`).once('value').then(function(snapshot) {
// Handle Promise
const tokenOfGroup = snapshot.val()
// get tokens from the database at particular location get values
const valuess = Object.keys(tokenOfGroup).map(k => tokenOfGroup[k]);
//console.log(' ____________ddd((999999ddd_________________ ' + valuess );
const payload = {
notification: {
title: original.senderName + " :- ",
body: original.content
}
};
return admin.messaging().sendToDevice(valuess, payload);
}, function(error) {
console.error(error);
});
return ;
} else {
// get token from the database at particular location
const tokenss = admin.database().ref(`/users/${toIDUser}/credentials`).once('value').then(function(snapshot) {
// Handle Promise
// The Promise was "fulfilled" (it succeeded).
const credentials = snapshot.val()
// console.log('snapshot ......snapshot.val().name****^^^^^^^^^^^^kensPromise****** :- ', credentials.name);
//console.log('snapshot.....****snapshot.val().token****^^^^^^^^^^^^kensPromise****** :- ', credentials.token);
const deviceToken = credentials.token;
const payload = {
notification: {
title: original.senderName + " :- ",
body: original.content
}
};
return admin.messaging().sendToDevice(deviceToken, payload);
}, function(error) {
console.error(error);
});
}
return ;
});
1)订阅相同的主题名称,例如:
2)在应用程序内部发送消息
您可以使用改造。为设备订阅主题新闻。从一台设备向另一台设备发送通知。
public void onClick(View view) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", "key=legacy server key from FB console"); // <-- this is the important line
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
httpClient.addInterceptor(logging);
OkHttpClient client = httpClient.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://fcm.googleapis.com")//url of FCM message server
.client(client)
.addConverterFactory(GsonConverterFactory.create())//use for convert JSON file into object
.build();
// prepare call in Retrofit 2.0
FirebaseAPI firebaseAPI = retrofit.create(FirebaseAPI.class);
//for messaging server
NotifyData notifydata = new NotifyData("Notification title","Notification body");
Call<Message> call2 = firebaseAPI.sendMessage(new Message("topic or deviceID", notifydata));
call2.enqueue(new Callback<Message>() {
@Override
public void onResponse(Call<Message> call, Response<Message> response) {
Log.d("Response ", "onResponse");
t1.setText("Notification sent");
}
@Override
public void onFailure(Call<Message> call, Throwable t) {
Log.d("Response ", "onFailure");
t1.setText("Notification failure");
}
});
}
POJO
public class Message {
String to;
NotifyData notification;
public Message(String to, NotifyData notification) {
this.to = to;
this.notification = notification;
}
}
和
public class NotifyData {
String title;
String body;
public NotifyData(String title, String body ) {
this.title = title;
this.body = body;
}
}
和 FirebaseAPI
public interface FirebaseAPI {
@POST("/fcm/send")
Call<Message> sendMessage(@Body Message message);
}
如果您有要向其发送通知的设备的 fcm(gcm) 令牌。这只是发送通知的发布请求。
就我而言,我对此类消息使用改造:
public class Message {
private String to;
private String collapseKey;
private Notification notification;
private Data data;
public Message(String to, String collapseKey, Notification notification, Data data) {
this.to = to;
this.collapseKey = collapseKey;
this.notification = notification;
this.data = data;
}
}
数据
public class Data {
private String body;
private String title;
private String key1;
private String key2;
public Data(String body, String title, String key1, String key2) {
this.body = body;
this.title = title;
this.key1 = key1;
this.key2 = key2;
}
}
通知
public class Notification {
private String body;
private String title;
public Notification(String body, String title) {
this.body = body;
this.title = title;
}
}
这个电话
private void sentToNotification() {
String to = "YOUR_TOKEN";
String collapseKey = "";
Notification notification = new Notification("Hello bro", "title23");
Data data = new Data("Hello2", "title2", "key1", "key2");
Message notificationTask = new Message(to, collapseKey, notification, data);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://fcm.googleapis.com/")//url of FCM message server
.addConverterFactory(GsonConverterFactory.create())//use for convert JSON file into object
.build();
ServiceAPI api = new retrofit.create(ServiceAPI.class);
Call<Message> call = api .sendMessage("key=YOUR_KEY", notificationTask);
call.enqueue(new Callback<Message>() {
@Override
public void onResponse(Call<Message> call, retrofit2.Response<Message> response) {
Log.d("TAG", response.body().toString());
}
@Override
public void onFailure(Call<Message> call, Throwable t) {
Log.e("TAG", t.getMessage());
}
});
}
我们的 ServiceAPI
public interface ServiceAPI {
@POST("/fcm/send")
Call<Message> sendMessage(@Header("Authorization") String token, @Body Message message);
}
Google Cloud Functions 现在可以在没有应用服务器的情况下从设备到设备发送推送通知。
从Google Cloud Functions的相关页面:
开发人员可以使用 Cloud Functions 来保持用户的参与度并及时了解有关应用程序的相关信息。例如,考虑一个允许用户在应用程序中关注彼此活动的应用程序。在这样的应用程序中,由实时数据库写入触发以存储新关注者的功能可以创建 Firebase 云消息传递 (FCM) 通知,让适当的用户知道他们获得了新关注者。
例子:
该函数在写入存储关注者的实时数据库路径时触发。
该函数编写要通过 FCM 发送的消息。
FCM 将通知消息发送到用户的设备。
您可以使用 firebase 实时数据库来执行此操作。您可以创建用于存储聊天的数据结构,并为两个用户的对话线程添加观察者。它仍然是设备 - 服务器 - 设备架构,但在这种情况下,开发人员没有额外的服务器。这使用了 firebase 服务器。您可以在此处查看教程(忽略 UI 部分,不过,这也是聊天 UI 框架的一个很好的起点)。
以下是如何在没有第二台服务器的情况下获取通知,除了 Firebase 一个。所以我们只使用 Firebase,没有额外的服务器。
在移动应用程序代码中,我们通过像这里这样的 Android 库创建自己的通知功能,而不使用像这里这样的 Firebase 库,没有 Firebase Cloud 消息传递。以下是 Kotlin 的示例:
私人乐趣通知(){ createNotificationChannel()
val intent = Intent(this, LoginActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
val notificationBuilder = NotificationCompat.Builder(this, "yuh_channel_id")
.setSmallIcon(R.drawable.ic_send)
.setContentText("yuh")
.setContentText("yuh")
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(0, notificationBuilder.build())
with(NotificationManagerCompat.from(this)) {
// notificationId is a unique int for each notification that you must define
notify(0, notificationBuilder.build())
}
}
private fun createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = "yuh_channel"
val descriptionText = "yuh_description"
val importance = NotificationManager.IMPORTANCE_DEFAULT
val CHANNEL_ID = "yuh_channel_id"
val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
description = descriptionText
}
// Register the channel with the system
val notificationManager: NotificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
在 Firebase 数据库中,创建集合“待处理通知”。文档应包含用户名(将通知发送到)和源名称(用户在点击通知时应该去哪里)。
在应用程序代码中,实现将新记录添加到 Pending Notifications 集合的选项。例如。如果用户 A 向用户 B 发送消息,则在集合中创建 ID 为用户 B(将被通知)的文档。
在应用程序代码中,设置后台(当应用程序对用户不可见时)服务。喜欢这里。在后台服务中,为“Notifications Pending”集合中的更改设置侦听器。当带有用户 id 的新记录进入集合时,调用上文第 1 段中创建的通知函数并从集合中删除后续记录。
所以我在这里有了一个想法。请参阅:如果 FCM 和 GCM 都有一个指向 http 请求的端点,我们可以在其中发送带有我们的消息数据的 post json,包括我们希望传递此消息的设备的令牌。
那么为什么不向 Firebase 服务器发送一条带有此通知的帖子以发送给用户 B 呢?你明白 ?
因此,如果用户在后台使用您的应用程序,您可以发送消息并与通话帖子聊天,以确保发送通知。我也很快需要它,我稍后会测试。你说什么?
最简单的方法:
void sendFCMPush(String msg,String token) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", "key="+Const.FIREBASE_LEGACY_SERVER_KEY); // <-- this is the important line
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
httpClient.addInterceptor(logging);
OkHttpClient client = httpClient.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://fcm.googleapis.com/")//url of FCM message server
.client(client)
.addConverterFactory(GsonConverterFactory.create())//use for convert JSON file into object
.build();
// prepare call in Retrofit 2.0
FirebaseAPI firebaseAPI = retrofit.create(FirebaseAPI.class);
//for messaging server
NotifyData notifydata = new NotifyData("Chatting", msg);
Call<Message> call2 = firebaseAPI.sendMessage(new Message(token, notifydata));
call2.enqueue(new Callback<Message>() {
@Override
public void onResponse(Call<Message> call, retrofit2.Response<Message> response) {
Log.e("#@ SUCCES #E$#", response.body().toString());
}
@Override
public void onFailure(Call<Message> call, Throwable t) {
Log.e("E$ FAILURE E$#", t.getMessage());
}
});
}
创建类以制作对象:
public class Message {
String to;
NotifyData data;
public Message(String to, NotifyData data) {
this.to = to;
this.data = data;
}
}
创建类以制作对象:
public class Notification {
String title;
String message;
enter code here`enter code here`
public Notification(String title, String message) {
this.title = title;
this.message = message;
}
}