具有解析服务器推送通知的FCM mismatchsenderid和客户端应用程序错误

时间:2018-04-15 15:19:51

标签: c# android firebase parse-platform push-notification

我曾经尝试使用GCM,但是我无法使用Parse Server。所以我采用了stackoverflow用户的建议并尝试使用FCM。

我的设备从FCM获取注册ID,如下所示:

04-15 17:01:29.773 I/parse.GcmRegistrar(30144): GCM registration successful. Registration Id: APA91bFoNUPYdsjN6O_CkPje-O0hXjNz9kvURZMex72xClyBr_5o6D0vYtI-F0iyAGgSYjpIEaJt2QQ2CXk2qpI11gPFUSUdzH-NxQRXSK3hPkuaiC_lciVV3E0fp6A_VZUoYJ8VxOIh

我尝试从firebase控制台发送一个带有此ID的通知,并且它的工作我的事件被触发了,一切都很好。

当我想使用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

这个是奇怪的,因为我的清单包含gcm_sender_id加上它包含前缀id:这是我的清单

<?xml version="1.0" encoding="utf-8"?>

    

<uses-permission android:name="android.permission.INTERNET" />


<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<uses-permission android:name="android.permission.VIBRATE" />

<uses-permission android:name="android.permission.WAKE_LOCK" />

<uses-permission android:name="android.permission.GET_ACCOUNTS" />

<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

<permission android:name="com.companyname.appname.permission.C2D_MESSAGE" android:protectionLevel="signature" />

<uses-permission android:name="com.companyname.appname.permission.C2D_MESSAGE" />

<application android:label="Fuse.Android" android:icon="@mipmap/ic_launcher">

    <service android:name="parse.ParsePushService" />

    <receiver android:name="parse.ParsePushBroadcastReceiver"

    android:permission="com.google.android.c2dm.permission.SEND">

        <intent-filter>


            <action android:name="com.google.android.c2dm.intent.RECEIVE" />

            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

            <category android:name="com.companyname.appname" />

        </intent-filter>

    </receiver>
    <meta-data android:name="com.parse.push.gcm_sender_id"
                    android:value="id:767075137222"/>
</application>

我在网上搜索,人们说当你没有使用正确的API KEY&amp;发件人ID ..我正在使用这些:

enter image description here

接下来,我的Parse Server索引如下所示:

    // 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);

我已将GCM_SENDER_ID和GCM_API_KEY定义为Heroku主机Parse的配置变量。

在我从客户端应用程序调用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=[] 

我已经好几天了。有人可以告诉我,我试图做什么是可能的,如果有可能我可能做错了什么?

2 个答案:

答案 0 :(得分:0)

如果您使用的是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 -->

答案 1 :(得分:0)

遇到此错误的任何人:

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

但是已经定义了androidmanifest中的gcm_sender_id,很可能是安装了错误的sdk或parse.dll。我做的是我下载了parseplatform github中提供的开源SDK,并修改了GcmRegistrar.cs类,不为sender_id返回null:

这花了我很长时间,但对于遇到同样问题的人请下载最新的.dll,或者如果问题仍然存在,则意味着dll没有更新,你必须手动执行此操作。在我的情况下,我使用.NET Sdk并且它没有更新。

下载开源sdk并用此替换Internal / Push / GcmRegistrar.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.
        }
      }
    }
  }
}