GCM отправляет одно и то же сообщение несколько раз (PushSharp)

Проблема:

Я разрабатываю приложение для Android с помощью Xamarin, которое использует PushSharp. Я использую GCM для отправки сообщений клиентам, чтобы я мог обновлять определенные вещи, если приложение открыто. Похоже, что GCM отправляет одно и то же сообщение на одно и то же устройство несколько раз.


Логкат:

Thread started:  #12
09-17 08:40:34.307 I/PushSharp-GCM(20855): GCM Message Received!
09-17 08:40:34.317 V/GCMBaseIntentService(20855): Releasing Wakelock
09-17 08:40:34.327 V/UpdateSignalReceiver(20855): Message Receieved: *****
Thread finished:  #12
The thread 'Unknown' (0xc) has exited with code 0 (0x0).
09-17 08:40:34.787 V/PushHandlerBroadcastReceiver(20855): OnReceive: com.google.android.c2dm.intent.RECEIVE
09-17 08:40:34.787 V/PushHandlerBroadcastReceiver(20855): GCM IntentService Class: rAMP_TabletV1.x5.GCMIntentService
09-17 08:40:34.787 V/GCMBaseIntentService(20855): Acquiring wakelock
Thread started:  #13
09-17 08:40:34.807 I/PushSharp-GCM(20855): GCM Message Received!
09-17 08:40:34.817 V/GCMBaseIntentService(20855): Releasing Wakelock
09-17 08:40:34.817 V/UpdateSignalReceiver(20855): Message Receieved: *****
Thread finished:  #13
The thread 'Unknown' (0xd) has exited with code 0 (0x0).
09-17 08:40:35.817 V/PushHandlerBroadcastReceiver(20855): OnReceive: com.google.android.c2dm.intent.RECEIVE
09-17 08:40:35.817 V/PushHandlerBroadcastReceiver(20855): GCM IntentService Class: rAMP_TabletV1.x5.GCMIntentService
09-17 08:40:35.817 V/GCMBaseIntentService(20855): Acquiring wakelock
Thread started:  #14
09-17 08:40:35.857 I/PushSharp-GCM(20855): GCM Message Received!
09-17 08:40:35.857 V/GCMBaseIntentService(20855): Releasing Wakelock
09-17 08:40:35.867 V/UpdateSignalReceiver(20855): Message Receieved: *****
Thread finished:  #14
The thread 'Unknown' (0xe) has exited with code 0 (0x0).
09-17 08:40:36.277 V/PushHandlerBroadcastReceiver(20855): OnReceive: com.google.android.c2dm.intent.RECEIVE
09-17 08:40:36.277 V/PushHandlerBroadcastReceiver(20855): GCM IntentService Class: rAMP_TabletV1.x5.GCMIntentService
09-17 08:40:36.277 V/GCMBaseIntentService(20855): Acquiring wakelock
Thread started:  #15
09-17 08:40:36.327 I/PushSharp-GCM(20855): GCM Message Received!
09-17 08:40:36.327 V/GCMBaseIntentService(20855): Releasing Wakelock
09-17 08:40:36.337 V/UpdateSignalReceiver(20855): Message Receieved: *****
Thread finished:  #15
The thread 'Unknown' (0xf) has exited with code 0 (0x0).
09-17 08:40:36.717 V/PushHandlerBroadcastReceiver(20855): OnReceive: com.google.android.c2dm.intent.RECEIVE
09-17 08:40:36.717 V/PushHandlerBroadcastReceiver(20855): GCM IntentService Class: rAMP_TabletV1.x5.GCMIntentService
09-17 08:40:36.717 V/GCMBaseIntentService(20855): Acquiring wakelock
Thread started:  #16
09-17 08:40:36.747 I/PushSharp-GCM(20855): GCM Message Received!
09-17 08:40:36.757 V/GCMBaseIntentService(20855): Releasing Wakelock
09-17 08:40:36.757 V/UpdateSignalReceiver(20855): Message Receieved: *****

Отправка сообщения:

Каждое устройство регистрируется, а регистрационный идентификатор хранится в базе данных. Я проверяю номер версии и предыдущий регистрационный идентификатор, чтобы убедиться, что нет дубликатов, а также удостоверяюсь, что у меня правильный регистрационный идентификатор. (Я дважды проверил, чтобы убедиться, что в моей базе данных нет дубликатов)

Обновление вызывается из службы WCF и отправляет сообщения на все зарегистрированные устройства. Метод вызывается только один раз, а AllRegisteredDevices — это отдельный список идентификаторов устройств, на которые нужно отправить сообщение.

foreach (var deviceId in AllRegisteredDevices)
{
    var webRequest = WebRequest.Create("https://android.googleapis.com/gcm/send");
    webRequest.Method = "post";
    webRequest.ContentType = " application/x-www-form-urlencoded;charset=UTF-8";
    webRequest.Headers.Add(string.Format("Authorization: key={0}", GoogleAppID));
    webRequest.Headers.Add(string.Format("Sender: id={0}", SENDER_ID));
    var postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message="
        + value + "&registration_id=" + deviceId + "";
    Byte[] bytes = Encoding.UTF8.GetBytes(postData);
    webRequest.ContentLength = bytes.Length;
    var dataStream = webRequest.GetRequestStream();
    dataStream.Write(bytes, 0, bytes.Length);
    dataStream.Close();
    var webResponse = webRequest.GetResponse();
    dataStream = webResponse.GetResponseStream();
    var streamReader = new StreamReader(dataStream);
    var responseFromServer = streamReader.ReadToEnd();
    streamReader.Close();
    dataStream.Close();
    webResponse.Close();
} // end loop

Получение сообщения:

У меня есть собственный широковещательный приемник для обработки сообщения, в зависимости от значения «сообщения». PushService передает его получателю.

Push-сервис

protected override void OnMessage(Context context, Intent intent)
{
     Log.Info(PushHandlerBroadcastReceiver.TAG, "GCM Message Received!");

     string message = intent.Extras.GetString("message");
     var theIntent = new Intent(UpdateAction);
     theIntent.PutExtra("message", message);
     SendOrderedBroadcast(theIntent, null);
} // end OnMessage

ОбновлениеСигналРесивер

[BroadcastReceiver]
[IntentFilter(new string[]{PushHandlerService.UpdateAction}, Priority = (int)IntentFilterPriority.HighPriority)]
public class UpdateSignalReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {       
        MyActivity TheActivity = ((MyActivity )context);
        string message = intent.Extras.GetString("message") ?? "";
        Log.Verbose("UpdateSignalReceiver", "Message Receieved: " + message);
        if (message == "foo")
        {
            TheActivity.DoSomething();
        } // end if
        else if (message == "bar")
        {
            TheActivity.SomethingElse();
        } // end else if
        else
        {
            TheActivity.CatchAllMethod();
        } // end else
        InvokeAbortBroadcast();
    } // end on receieve
} // end UpdateSignalReceiver

Окружающая обстановка

  • Вкладка Samsung Galaxy 3
  • Только приложения, установленные на заводе (никаких других приложений, использующих тот же GCM)

Исследование:


Вопрос:

Почему я получаю одно и то же сообщение несколько раз, хотя отправляю его только один раз?


person silencedmessage    schedule 17.09.2014    source источник
comment
Значит, он попадает в OnMessage 1+ раз? Если нет, есть ли у вас другое установленное приложение, использующее тот же GCM?   -  person Casper Skoubo    schedule 17.09.2014
comment
Это верно, onmessage срабатывает несколько раз, обычно 3 раза, разделенных миллисекундами. Я использую исключительно Samsung Tab 3, и это единственное приложение, которое не установлено на заводе.   -  person silencedmessage    schedule 17.09.2014


Ответы (1)


Я решил пойти с троттлинговым подходом. Хотя это не идеально в своей реализации, общая идея такова:

  • Всем сообщениям присваивается уникальный идентификатор (Guid).
  • Широковещательный приемник имеет статический список Guids, содержащий последние 20 идентификаторов сообщений, которые мы получили и обработали.
  • Работайте только с сообщениями, идентификатор которых отсутствует в нашем списке, поэтому мы знаем, что это новое сообщение для этого устройства.
  • Ограничьте список до 20 идентификаторов, чтобы он не вышел из-под контроля. (20 кажется более чем достаточным, так как повторяющиеся сообщения обычно приходят в 3, а иногда и в 5 итерациях)

[BroadcastReceiver]
[IntentFilter(new string[]{PushHandlerService.UpdateAction}, Priority = (int)IntentFilterPriority.HighPriority)]
public class UpdateSignalReceiver : BroadcastReceiver
{
    private static List<Guid> _Last20MessageIds;

    public override void OnReceive(Context context, Intent intent)
    {       
        Guid MessageId;
        // Pull the MessageId from the intent
        String MessageIdString = intent.Extras.GetString("message_id" ?? Guid.Empty.ToString());
        Guid.TryParse(MessageIdString, out MessageId);


        if (_Last20MessageIds == null)
        {
            _Last20MessageIds = new List<Guid>();
        }

        // Make sure we didn't already receive this Message, then do work
        if (MessageId != null && MessageId != Guid.Empty && ! _Last20MessageIds.Contains(MessageId))
        {
            DoSomeWorkWithIntent(intent);


            // Add the guid to the message id list
            _Last20MessageIds.Insert(0, MessageId);

            // Trim the list to the most recent 20
            _Last20MessageIds= _Last20MessageIds.Take(20).ToList();
        }
        InvokeAbortBroadcast();
    } // end on receive
} // end UpdateSignalReceiver
person silencedmessage    schedule 26.02.2015