Firebase 静默 apns 通知
Firebase silent apns notification
有没有办法使用 google 的 firebase 发送静默 APNS?
似乎如果应用程序在后台运行,它将始终向用户显示通知。
谢谢?
您可以使用 FCM 服务器发送静默 APNS 消息API
https://firebase.google.com/docs/cloud-messaging/http-server-ref
特别需要使用:
- 数据字段:
This parameter specifies the custom key-value pairs of the message's
payload.
For example, with data:{"score":"3x1"}:
On iOS, if the message is sent via APNS, it represents the custom data
fields. If it is sent via FCM connection server, it would be
represented as key value dictionary in AppDelegate
application:didReceiveRemoteNotification:.
The key should not be a reserved word ("from" or any word starting
with "google" or "gcm"). Do not use any of the words defined in this
table (such as collapse_key).
Values in string types are recommended. You have to convert values in
objects or other non-string data types (e.g., integers or booleans) to
string
- content_available字段:
On iOS, use this field to represent content-available in the APNS
payload. When a notification or message is sent and this is set to
true, an inactive client app is awoken. On Android, data messages wake
the app by default. On Chrome, currently not supported.
完整文档:
https://firebase.google.com/docs/cloud-messaging/http-server-ref#downstream-http-messages-json
我在我的博客上更详细地解释了这个主题。
http://blog.boxstory.com/2017/01/how-to-send-silent-push-notification-in.html
** 关键点是:"content_available:true"
这是示例 JSON
{
"to" : "<device>",
"priority": "normal",
"content_available": true, <-- this key is converted to 'content-available:1'
"notification" : {
"body" : "noti body",
"title" : "noti title",
"link": "noti link "
}
}
Note: If the above sample JSON is sent, then the notification will be
visible to the user. Use below If you don't want the user to see the
push notification.
{
"to": "<device>",
"priority": "normal",
"content_available": true <-- this key is converted to 'content-available:1'
}
对于使用 FCM 服务器的真正静默通知(前台和后台),请使用这些字段:
"to" : "[token]",
"content_available": true,
"priority": "high",
"data" : {
"key1" : "abc",
"key2" : 123
}
注意:确保您使用的是 "content_available" NOT "content-available" 和 FCM。它是为 APNS 转换的,否则将无法正确接收。这种差异让我困惑了一段时间。
对于不使用其他答案中显示的 Legacy HTTP
而使用最新的 v1 HTTP protocol
的人,我终于找到了发送静默通知的正确方法。
NodeJS 示例使用 firebase-admin
:
const message = {
apns: {
payload: {
aps: {
"content-available": 1,
alert: ""
}
}
},
token: "[token here - note that you can also replace the token field with `topic` or `condition` depending on your targeting]"
};
admin
.messaging()
.send(message)
.then(response => {
// Response is a message ID string.
console.log("Successfully sent message:", response);
})
.catch(error => {
console.log("Error sending message:", error);
});
解释:
- 似乎
apns
中的有效载荷在 v1 HTTP protocol
中没有被 Firebase 转换,所以你需要原始的 "content-available": 1
。
alert: ""
也是必须的。如果您曾尝试使用 Pusher
之类的方式发送静默通知,您会发现只有 content-available
无法触发它。相反,添加其他字段(例如 sound
或 alert
可以使其工作。参见 Silent Push Notification in iOS 7 does not work。由于 Firebase 禁止空声音,我们可以为此使用空警报。
其他解决方案对我不起作用。
我想要一个向 iOS 和 Android.
发送数据消息的解决方案
根据我的测试,我发现当我的 iOS 应用程序在后台时可靠地发送数据消息的唯一方法是包含一个空的通知负载。
此外,正如其他答案提到的,您需要包括 content_available
和 priority
。
要使用 curl 命令对此进行测试,您需要 FCM server key 和应用程序中的 FCM 令牌。
仅 iOS 的 curl 命令示例。 (无可见通知的可靠数据消息)
curl -X POST \
https://fcm.googleapis.com/fcm/send \
-H 'authorization: key=server_key_here' \
-H 'content-type: application/json' \
-d '{
"to": "fcm_token_here",
"priority": "high",
"content_available": true,
"notification": {
"empty": "body"
},
"data": {
"key1": "this_is_a_test",
"key2": "abc",
"key3": "123456",
}
}'
将上面的 server_key_here
和 fcm_token_here
替换为您自己的。
当应用程序处于后台且不应显示 UI 消息时,应调用 AppDelegate
class 中的以下方法。
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
//get data from userInfo
completionHandler(UIBackgroundFetchResult.newData)
}
以下是使用云函数和打字稿发送到主题的方法。
const payload = {
notification: {
empty: "message"
},
data: {
key1: "some_value",
key2: "another_value",
key3: "one_more"
}
}
const options = {
priority: "high",
contentAvailable: true //wakes up iOS
}
return admin.messaging().sendToTopic("my_topic", payload, options)
.then(response => {
console.log(`Log some stuff`)
})
.catch(error => {
console.log(error);
});
以上似乎始终适用于 iOS,有时适用于 Android。
我得出的结论是,我的后端需要在发送推送通知之前确定平台才能最有效。
我需要向主题发送预定通知。以上对我来说都不起作用,但我终于让应用程序委托 application(application:didReceiveRemoteNotification:fetchCompletionHandler:)
始终如一地被调用。这是我最终在 index.js
云函数文件中所做的完整示例(请注意,您需要 "apns-push-type": "background"
和 "apns-priority": "5"
headers,以及 "content-available": 1
里面的条目 aps
object):
const admin = require("firebase-admin");
const functions = require("firebase-functions");
exports.sendBackgroundFetchNotification = functions.pubsub.schedule("every 1 hours").onRun((context) => {
const message = {
data: {},
apns: {
headers: {
"apns-push-type": "background",
"apns-priority": "5",
},
payload: {
aps: {
"content-available": 1,
"alert": {},
},
},
},
topic: "[Topic_Name_Here]",
};
return admin
.messaging()
.send(message)
.then(response => {
// Response is a message ID string.
console.log("Successfully sent message:", response);
return null;
})
.catch(error => {
console.log("Error sending message:", error);
return null;
});
});
如果您不想在部署后等待函数触发,只需进入 Google 云控制台函数部分 (https://console.cloud.google.com/functions/list) 并单击函数名称,然后点击“测试”,最后点击“测试功能”。
值得注意的是,此代码使用 FCM 较新的 HTTP v1 协议,它允许您根据 Apple 的规范(下面的有用链接)构建消息 object。
https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification
有没有办法使用 google 的 firebase 发送静默 APNS? 似乎如果应用程序在后台运行,它将始终向用户显示通知。
谢谢?
您可以使用 FCM 服务器发送静默 APNS 消息API https://firebase.google.com/docs/cloud-messaging/http-server-ref
特别需要使用:
- 数据字段:
This parameter specifies the custom key-value pairs of the message's payload.
For example, with data:{"score":"3x1"}:
On iOS, if the message is sent via APNS, it represents the custom data fields. If it is sent via FCM connection server, it would be represented as key value dictionary in AppDelegate application:didReceiveRemoteNotification:.
The key should not be a reserved word ("from" or any word starting with "google" or "gcm"). Do not use any of the words defined in this table (such as collapse_key).
Values in string types are recommended. You have to convert values in objects or other non-string data types (e.g., integers or booleans) to string
- content_available字段:
On iOS, use this field to represent content-available in the APNS payload. When a notification or message is sent and this is set to true, an inactive client app is awoken. On Android, data messages wake the app by default. On Chrome, currently not supported.
完整文档: https://firebase.google.com/docs/cloud-messaging/http-server-ref#downstream-http-messages-json
我在我的博客上更详细地解释了这个主题。 http://blog.boxstory.com/2017/01/how-to-send-silent-push-notification-in.html
** 关键点是:"content_available:true"
这是示例 JSON
{
"to" : "<device>",
"priority": "normal",
"content_available": true, <-- this key is converted to 'content-available:1'
"notification" : {
"body" : "noti body",
"title" : "noti title",
"link": "noti link "
}
}
Note: If the above sample JSON is sent, then the notification will be visible to the user. Use below If you don't want the user to see the push notification.
{
"to": "<device>",
"priority": "normal",
"content_available": true <-- this key is converted to 'content-available:1'
}
对于使用 FCM 服务器的真正静默通知(前台和后台),请使用这些字段:
"to" : "[token]",
"content_available": true,
"priority": "high",
"data" : {
"key1" : "abc",
"key2" : 123
}
注意:确保您使用的是 "content_available" NOT "content-available" 和 FCM。它是为 APNS 转换的,否则将无法正确接收。这种差异让我困惑了一段时间。
对于不使用其他答案中显示的 Legacy HTTP
而使用最新的 v1 HTTP protocol
的人,我终于找到了发送静默通知的正确方法。
NodeJS 示例使用 firebase-admin
:
const message = {
apns: {
payload: {
aps: {
"content-available": 1,
alert: ""
}
}
},
token: "[token here - note that you can also replace the token field with `topic` or `condition` depending on your targeting]"
};
admin
.messaging()
.send(message)
.then(response => {
// Response is a message ID string.
console.log("Successfully sent message:", response);
})
.catch(error => {
console.log("Error sending message:", error);
});
解释:
- 似乎
apns
中的有效载荷在v1 HTTP protocol
中没有被 Firebase 转换,所以你需要原始的"content-available": 1
。 alert: ""
也是必须的。如果您曾尝试使用Pusher
之类的方式发送静默通知,您会发现只有content-available
无法触发它。相反,添加其他字段(例如sound
或alert
可以使其工作。参见 Silent Push Notification in iOS 7 does not work。由于 Firebase 禁止空声音,我们可以为此使用空警报。
其他解决方案对我不起作用。 我想要一个向 iOS 和 Android.
发送数据消息的解决方案根据我的测试,我发现当我的 iOS 应用程序在后台时可靠地发送数据消息的唯一方法是包含一个空的通知负载。
此外,正如其他答案提到的,您需要包括 content_available
和 priority
。
要使用 curl 命令对此进行测试,您需要 FCM server key 和应用程序中的 FCM 令牌。
仅 iOS 的 curl 命令示例。 (无可见通知的可靠数据消息)
curl -X POST \
https://fcm.googleapis.com/fcm/send \
-H 'authorization: key=server_key_here' \
-H 'content-type: application/json' \
-d '{
"to": "fcm_token_here",
"priority": "high",
"content_available": true,
"notification": {
"empty": "body"
},
"data": {
"key1": "this_is_a_test",
"key2": "abc",
"key3": "123456",
}
}'
将上面的 server_key_here
和 fcm_token_here
替换为您自己的。
当应用程序处于后台且不应显示 UI 消息时,应调用 AppDelegate
class 中的以下方法。
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
//get data from userInfo
completionHandler(UIBackgroundFetchResult.newData)
}
以下是使用云函数和打字稿发送到主题的方法。
const payload = {
notification: {
empty: "message"
},
data: {
key1: "some_value",
key2: "another_value",
key3: "one_more"
}
}
const options = {
priority: "high",
contentAvailable: true //wakes up iOS
}
return admin.messaging().sendToTopic("my_topic", payload, options)
.then(response => {
console.log(`Log some stuff`)
})
.catch(error => {
console.log(error);
});
以上似乎始终适用于 iOS,有时适用于 Android。 我得出的结论是,我的后端需要在发送推送通知之前确定平台才能最有效。
我需要向主题发送预定通知。以上对我来说都不起作用,但我终于让应用程序委托 application(application:didReceiveRemoteNotification:fetchCompletionHandler:)
始终如一地被调用。这是我最终在 index.js
云函数文件中所做的完整示例(请注意,您需要 "apns-push-type": "background"
和 "apns-priority": "5"
headers,以及 "content-available": 1
里面的条目 aps
object):
const admin = require("firebase-admin");
const functions = require("firebase-functions");
exports.sendBackgroundFetchNotification = functions.pubsub.schedule("every 1 hours").onRun((context) => {
const message = {
data: {},
apns: {
headers: {
"apns-push-type": "background",
"apns-priority": "5",
},
payload: {
aps: {
"content-available": 1,
"alert": {},
},
},
},
topic: "[Topic_Name_Here]",
};
return admin
.messaging()
.send(message)
.then(response => {
// Response is a message ID string.
console.log("Successfully sent message:", response);
return null;
})
.catch(error => {
console.log("Error sending message:", error);
return null;
});
});
如果您不想在部署后等待函数触发,只需进入 Google 云控制台函数部分 (https://console.cloud.google.com/functions/list) 并单击函数名称,然后点击“测试”,最后点击“测试功能”。
值得注意的是,此代码使用 FCM 较新的 HTTP v1 协议,它允许您根据 Apple 的规范(下面的有用链接)构建消息 object。
https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification