C# FCM与解析服务器推送通知不匹配SenderId和客户端应用程序错误
我曾经尝试使用GCM,但我无法让它与解析服务器一起工作。。所以我采纳了stackoverflow用户的建议,并尝试使用FCM 我的设备从FCM获取注册id,如下所示:C# FCM与解析服务器推送通知不匹配SenderId和客户端应用程序错误,c#,android,firebase,parse-platform,push-notification,C#,Android,Firebase,Parse Platform,Push Notification,我曾经尝试使用GCM,但我无法让它与解析服务器一起工作。。所以我采纳了stackoverflow用户的建议,并尝试使用FCM 我的设备从FCM获取注册id,如下所示: 04-15 17:01:29.773 I/parse.GcmRegistrar(30144): GCM registration successful. Registration Id: APA91bFoNUPYdsjN6O_CkPje-O0hXjNz9kvURZMex72xClyBr_5o6D0vYtI-F0iyAGgSYjpI
04-15 17:01:29.773 I/parse.GcmRegistrar(30144): GCM registration successful. Registration Id: APA91bFoNUPYdsjN6O_CkPje-O0hXjNz9kvURZMex72xClyBr_5o6D0vYtI-F0iyAGgSYjpIEaJt2QQ2CXk2qpI11gPFUSUdzH-NxQRXSK3hPkuaiC_lciVV3E0fp6A_VZUoYJ8VxOIh
// Example express application adding the parse-server module to expose Parse
// compatible API routes.
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var path = require('path');
var databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
var pushConfig = {};
if (process.env.GCM_SENDER_ID && process.env.GCM_API_KEY) {
pushConfig['android'] = {
senderId: process.env.GCM_SENDER_ID || '',
apiKey: process.env.GCM_API_KEY || ''};
}
var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'myAppId',
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse', // Don't forget to change to https if needed
push: pushConfig,
liveQuery: {
classNames: ["Posts", "Comments"] // List of classes to support for query subscriptions
}
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey
var app = express();
// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));
// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);
// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
res.status(200).send('I dream of being a website. Please star the parse-server repo on GitHub!');
});
// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function(req, res) {
res.sendFile(path.join(__dirname, '/public/test.html'));
});
var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
// This will enable the Live Query real-time server
ParseServer.createLiveQueryServer(httpServer);
我试图用这个ID从firebase控制台发送一个通知,它正在工作。我的事件被触发,一切正常
当我想使用ParseCloud函数向我的用户发送通知时,问题就出现了。在搜索设备输出日志以查找错误时,我发现了以下错误:
04-15 17:01:25.490 E/parse.GcmRegistrar(30144): Found com.parse.push.gcm_sender_id <meta-data> element with value "id:767075137222", but the value is missing the expected "id:" prefix
我已经为Heroku宿主解析的配置变量定义了GCM_SENDER_ID和GCM_API_键
在我从客户端应用程序调用ParseCloud函数后,我在heroku日志中看到:
Apr 15 08:03:02 fuseparse app/web.1: } method=POST, url=/parse/push, host=fuseparse.herokuapp.com, connection=close, user-agent=node-XMLHttpRequest, Parse/js1.11.1 (NodeJS 9.11.1), accept=*/*, content-type=text/plain, x-request-id=ea046fd0-5fb7-46b7-9ceb-e6a0fd2ebad1, x-forwarded-for=54.81.77.161, x-forwarded-proto=https, x-forwarded-port=443, via=1.1 vegur, connect-time=0, x-request-start=1523804582292, total-route-time=0, content-length=270, installationId=e2dc9f85-3c2f-464e-beca-c8b9d2cba528, alert=The Giants scored!
Apr 15 08:03:02 fuseparse app/web.1: verbose: RESPONSE from [POST] /parse/push: {
Apr 15 08:03:02 fuseparse app/web.1: "headers": {
Apr 15 08:03:02 fuseparse app/web.1: "X-Parse-Push-Status-Id": "upnMh1652U"
Apr 15 08:03:02 fuseparse app/web.1: },
Apr 15 08:03:02 fuseparse app/web.1: "response": {
Apr 15 08:03:02 fuseparse app/web.1: "result": true
Apr 15 08:03:02 fuseparse app/web.1: }
Apr 15 08:03:02 fuseparse app/web.1: } X-Parse-Push-Status-Id=upnMh1652U, result=true
Apr 15 08:03:02 fuseparse app/web.1: #### PUSH OK
Apr 15 08:03:02 fuseparse app/web.1: verbose: _PushStatus upnMh1652U: sending push to installations with 1 batches
Apr 15 08:03:02 fuseparse app/web.1: verbose: Sending push to 1
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM sending to 1 device
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM GCM Response: {
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "multicast_id": 5516369214301735000,
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "success": 0,
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "failure": 1,
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "canonical_ids": 0,
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "results": [
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM {
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM "error": "MismatchSenderId"
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM }
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM ]
Apr 15 08:03:02 fuseparse app/web.1: node-pre-gyp verb parse-server-push-adapter GCM }
Apr 15 08:03:02 fuseparse app/web.1: verbose: _PushStatus upnMh1652U: sent push! 0 success, 1 failures
Apr 15 08:03:02 fuseparse app/web.1: verbose: _PushStatus upnMh1652U: needs cleanup devicesToRemove=[]
我已经做了好几天了。。有人能告诉我我想做的是可能的吗?如果可能的话,我哪里做错了 如果您使用fcm通知,您需要将其添加到您的清单中
<!-- Firebase Notifications -->
<service android:name=".HERE_YOUR_CLASS_WHICH_EXTENDS_FirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<service android:name=".HERE_YOUR_CLASS_WHICH_EXTENDS_FirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
<!-- ./Firebase Notifications -->
任何对此错误有问题的人:
04-15 17:01:25.490 E/parse.GcmRegistrar(30144): Found com.parse.push.gcm_sender_id <meta-data> element with value "id:767075137222", but the value is missing the expected "id:" prefix
04-15 17:01:25.490 E/parse.gcmregistar(30144):找到值为“id:767075137222”的com.parse.push.gcm_sender_id元素,但该值缺少预期的“id:”前缀
但是在androidmanifest中定义了gcm_sender_id,很可能安装了错误的sdk或parse.dll。我所做的是下载了parseplatform github中提供的开源SDK,并修改了gcmregistar.cs类,使发送方id不返回null:
这花了我很长时间,但是对于任何有相同问题的人,请下载最新的.dll,或者如果问题仍然存在,这意味着dll没有更新,您必须手动执行此操作。在我的例子中,我使用的是.NET Sdk,它没有更新
下载开放源代码sdk并将Internal/Push/gcmregistar.cs替换为
using System;
using Android.App;
using Android.Content;
using Android.OS;
using System.Threading.Tasks;
namespace Parse {
internal class GcmRegistrar {
private const string LogTag = "parse.GcmRegistrar";
private const string ExtraRegistrationId = "registration_id";
private const string ExtraSenderId = "com.parse.push.gcm_sender_id";
private const string ParseGcmSenderId = "1076345567071";
public const string IntentRegisterAction = "com.google.android.c2dm.intent.REGISTER";
private readonly Object mutex = new Object();
private Request request;
private Context context;
public static GcmRegistrar GetInstance() {
return Singleton.Instance;
}
private static class Singleton {
public static readonly GcmRegistrar Instance = new GcmRegistrar(Application.Context);
}
private GcmRegistrar(Context context) {
this.context = context;
}
private string getActualSenderIdFromExtra(Object senderIdExtra) {
if (senderIdExtra == null ) {
return null;
}
string senderId = senderIdExtra.ToString();
if (!senderId.StartsWith("id:")) {
return null;
}
return senderId.Substring(3);
}
public void Register() {
ParseInstallation installation = ParseInstallation.CurrentInstallation;
lock (mutex) {
if (installation.DeviceToken == null && request == null) {
var metadata = ManifestInfo.GetApplicationMetaData();
object senderIdExtra = null;
if (metadata != null) {
senderIdExtra = metadata.Get(ExtraSenderId);
}
string senderIds = ParseGcmSenderId;
if (senderIdExtra != null) {
string senderId = getActualSenderIdFromExtra(senderIdExtra);
if (senderId != null) {
senderIds += "," + senderId;
} else {
Android.Util.Log.Error("parse.GcmRegistrar", "Found " + ExtraSenderId + " <meta-data> element with value \""
+ senderIdExtra.ToString() + "\", but the value is missing the expected \"id:\" prefix");
}
}
request = Request.CreateAndSend(this.context, senderIds);
}
}
}
/// <summary>
/// Handles GCM registration intent from <see cref="ParsePushBroadcastReceiver"/> and saves the GCM registration
/// id as <see cref="ParseInstallation.CurrentInstallation"/> device token.
/// </summary>
/// <remarks>
/// Should be called by a broadcast receiver or service to handle GCM registration response
/// intent (com.google.android.c2dm.intent.REGISTRATION).
/// </remarks>
/// <param name="intent"></param>
public Task HandleRegistrationIntentAsync(Intent intent) {
if (intent.Action == ParsePushBroadcastReceiver.ActionGcmRegisterResponse) {
string registrationId = intent.GetStringExtra(ExtraRegistrationId);
if (registrationId != null && registrationId.Length > 0) {
Android.Util.Log.Info(LogTag, "GCM registration successful. Registration Id: " + registrationId);
ParseInstallation installation = ParseInstallation.CurrentInstallation;
// Set `pushType` via internal `Set` method since we want to skip mutability check.
installation.Set("pushType", "gcm");
installation.DeviceToken = registrationId;
return installation.SaveAsync();
}
}
return Task.FromResult(0);
}
/// <summary>
/// Encapsulates the GCM registration request-response, potentially using <c>AlarmManager</c> to
/// schedule retries if the GCM service is not available.
/// </summary>
private class Request {
private Context context;
private string senderId;
private PendingIntent appIntent;
public static Request CreateAndSend(Context context, string senderId) {
Request request = new Request(context, senderId);
request.Send();
return request;
}
private Request(Context context, string senderId) {
this.context = context;
this.senderId = senderId;
appIntent = PendingIntent.GetBroadcast(context, 0, new Intent(), 0);
}
private void Send() {
Intent intent = new Intent(IntentRegisterAction);
intent.SetPackage("com.google.android.gsf");
intent.PutExtra("sender", senderId);
intent.PutExtra("app", appIntent);
ComponentName name = null;
try {
name = context.StartService(intent);
} catch (Exception) {
// Do nothing.
}
}
}
}
}
使用系统;
使用Android.App;
使用Android.Content;
使用Android.OS;
使用System.Threading.Tasks;
名称空间解析{
内部类GCMRegistar{
private const string LogTag=“parse.gcmregistar”;
private const string extralregistrationid=“registration\u id”;
private const string ExtraSenderId=“com.parse.push.gcm\u sender\u id”;
私有常量字符串ParseGcmSenderId=“1076345567071”;
public const string intentregistAction=“com.google.android.c2dm.intent.REGISTER”;
私有只读对象互斥体=新对象();
私人请求;
私人语境;
公共静态gcmregistar GetInstance(){
返回Singleton.Instance;
}
私有静态类单例{
public static readonly gcmregistar Instance=new gcmregistar(Application.Context);
}
专用GCMRegistar(上下文){
this.context=上下文;
}
私有字符串getActualSenderIdFromExtra(对象senderIdExtra){
if(senderIdExtra==null){
返回null;
}
字符串senderId=senderIdExtra.ToString();
如果(!senderId.StartsWith(“id:)){
返回null;
}
返回senderId.Substring(3);
}
公开作废登记册(){
ParseInstallation=ParseInstallation.CurrentInstallation;
锁(互斥){
if(installation.DeviceToken==null&&request==null){
var metadata=ManifestInfo.GetApplicationMetaData();
对象senderIdExtra=null;
if(元数据!=null){
senderIdExtra=metadata.Get(ExtraSenderId);
}
字符串senderID=ParseGcmSenderId;
if(senderIdExtra!=null){
字符串senderId=getActualSenderIdFromExtra(senderIdExtra);
if(senderId!=null){
senderId+=“,”+senderId;
}否则{
Android.Util.Log.Error(“parse.gcmregistar”,“Found”+ExtraSenderId+”元素的值为“”
+senderIdExtra.ToString()+“\”,但该值缺少预期的\“id:\“前缀”);
}
}
request=request.CreateAndSend(this.context,senderID);
}
}
}
///
///处理GCM注册意图,并保存GCM注册
///id作为设备令牌。
///
///
///应由广播接收器或服务调用,以处理GCM注册响应
///intent(com.google.android.c2dm.intent.REGISTRATION)。
///
///
公共任务HandleRegistrationIntentAsync(意图){
if(intent.Action==ParsePushBroadcastReceiver.ActionGcmRegisterResponse){
string registrationId=intent.GetStringExtra(ExtraRegistrationId);
if(registrationId!=null&®istrationId.Length>0){
Android.Util.Log.Info(LogTag,“GCM注册成功。注册Id:”+registrationId);
ParseInstallation=ParseInstallation.CurrentInstallation;
//通过内部“Set”方法设置“pushType”,因为我们想跳过可变性检查。
安装组件(“推式”、“gcm”);
installation.DeviceToken=注册ID;
返回installation.SaveAsync();
}
}
返回Task.FromResult(0);
}
///
///封装GCM注册请求响应,可能使用AlarmManager
///如果GCM服务不可用,则计划重试。
///
私有类请求{
私人语境;
私有字符串senderId;
私人悬而未决的意图;
公共静态请求CreateAndSend(上下文上下文,字符串senderId){
请求=新请求(上下文,senderId);
request.Send();
返回请求;
}
私有请求(上下文,字符串senderId){
this.context=上下文;
this.senderId=senderId;
appIntent
04-15 17:01:25.490 E/parse.GcmRegistrar(30144): Found com.parse.push.gcm_sender_id <meta-data> element with value "id:767075137222", but the value is missing the expected "id:" prefix
using System;
using Android.App;
using Android.Content;
using Android.OS;
using System.Threading.Tasks;
namespace Parse {
internal class GcmRegistrar {
private const string LogTag = "parse.GcmRegistrar";
private const string ExtraRegistrationId = "registration_id";
private const string ExtraSenderId = "com.parse.push.gcm_sender_id";
private const string ParseGcmSenderId = "1076345567071";
public const string IntentRegisterAction = "com.google.android.c2dm.intent.REGISTER";
private readonly Object mutex = new Object();
private Request request;
private Context context;
public static GcmRegistrar GetInstance() {
return Singleton.Instance;
}
private static class Singleton {
public static readonly GcmRegistrar Instance = new GcmRegistrar(Application.Context);
}
private GcmRegistrar(Context context) {
this.context = context;
}
private string getActualSenderIdFromExtra(Object senderIdExtra) {
if (senderIdExtra == null ) {
return null;
}
string senderId = senderIdExtra.ToString();
if (!senderId.StartsWith("id:")) {
return null;
}
return senderId.Substring(3);
}
public void Register() {
ParseInstallation installation = ParseInstallation.CurrentInstallation;
lock (mutex) {
if (installation.DeviceToken == null && request == null) {
var metadata = ManifestInfo.GetApplicationMetaData();
object senderIdExtra = null;
if (metadata != null) {
senderIdExtra = metadata.Get(ExtraSenderId);
}
string senderIds = ParseGcmSenderId;
if (senderIdExtra != null) {
string senderId = getActualSenderIdFromExtra(senderIdExtra);
if (senderId != null) {
senderIds += "," + senderId;
} else {
Android.Util.Log.Error("parse.GcmRegistrar", "Found " + ExtraSenderId + " <meta-data> element with value \""
+ senderIdExtra.ToString() + "\", but the value is missing the expected \"id:\" prefix");
}
}
request = Request.CreateAndSend(this.context, senderIds);
}
}
}
/// <summary>
/// Handles GCM registration intent from <see cref="ParsePushBroadcastReceiver"/> and saves the GCM registration
/// id as <see cref="ParseInstallation.CurrentInstallation"/> device token.
/// </summary>
/// <remarks>
/// Should be called by a broadcast receiver or service to handle GCM registration response
/// intent (com.google.android.c2dm.intent.REGISTRATION).
/// </remarks>
/// <param name="intent"></param>
public Task HandleRegistrationIntentAsync(Intent intent) {
if (intent.Action == ParsePushBroadcastReceiver.ActionGcmRegisterResponse) {
string registrationId = intent.GetStringExtra(ExtraRegistrationId);
if (registrationId != null && registrationId.Length > 0) {
Android.Util.Log.Info(LogTag, "GCM registration successful. Registration Id: " + registrationId);
ParseInstallation installation = ParseInstallation.CurrentInstallation;
// Set `pushType` via internal `Set` method since we want to skip mutability check.
installation.Set("pushType", "gcm");
installation.DeviceToken = registrationId;
return installation.SaveAsync();
}
}
return Task.FromResult(0);
}
/// <summary>
/// Encapsulates the GCM registration request-response, potentially using <c>AlarmManager</c> to
/// schedule retries if the GCM service is not available.
/// </summary>
private class Request {
private Context context;
private string senderId;
private PendingIntent appIntent;
public static Request CreateAndSend(Context context, string senderId) {
Request request = new Request(context, senderId);
request.Send();
return request;
}
private Request(Context context, string senderId) {
this.context = context;
this.senderId = senderId;
appIntent = PendingIntent.GetBroadcast(context, 0, new Intent(), 0);
}
private void Send() {
Intent intent = new Intent(IntentRegisterAction);
intent.SetPackage("com.google.android.gsf");
intent.PutExtra("sender", senderId);
intent.PutExtra("app", appIntent);
ComponentName name = null;
try {
name = context.StartService(intent);
} catch (Exception) {
// Do nothing.
}
}
}
}
}