GCM 多次推送同一消息 (PushSharp)

Posted

技术标签:

【中文标题】GCM 多次推送同一消息 (PushSharp)【英文标题】:GCM Pushing The Same Message Multiple Times (PushSharp) 【发布时间】:2014-09-17 13:12:57 【问题描述】:

问题:

我正在使用 Xamarin 开发一个使用 PushSharp 的 android 应用程序。我正在使用 GCM 向客户端发送消息,因此如果应用程序打开,我可以更新某些内容。 GCM 似乎多次向同一设备发送相同的消息。


Logcat:

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: *****

发送消息:

每个设备都已注册,注册 ID 存储在数据库中。我检查版本号和之前的注册 id 以确保没有重复,并确保我有正确的注册 id。 (我已仔细检查以确保我的数据库中没有重复项)

从 WCF 服务调用更新,它将消息发送到所有注册的设备。该方法只被调用一次,AllRegisteredDevices 是发送消息的不同设备 ID 列表。

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 将其传递给接收者。

推送服务

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

环境

三星 Galaxy Tab 3 仅出厂安装的应用(没有其他应用使用相同的 GCM)

研究:

GCM Multiple Notifications - 与注册设备的维护有关,在我的情况下,它们都是唯一的,没有重复,并且可以肯定的是,在 GCM 调用中填充我的 AllRegisteredDevices 时,我选择了 distinct。 GCM Duplicated Messages - GCM bug dating back to Feb, 2013。我怀疑这个错误是否仍然存在,尽管它是可能的。

问题:

为什么我只发送一次却反复收到相同的消息?

【问题讨论】:

所以它最终出现在 OnMessage 1 次以上?如果没有,您是否使用相同的 GCM 安装了另一个应用程序? 没错,onmessage 会触发多次,通常以毫秒为间隔触发 3 次。我只使用三星 tab 3,这是唯一没有出厂安装的应用程序。 【参考方案1】:

我决定采用节流方法。虽然这在实现上并不完美,但总体思路如下:

所有消息都有一个唯一 ID (Guid) 广播接收器有一个静态的 Guid 列表,其中包含我们最近收到和处理的 20 个消息 ID 仅处理 ID 未包含在我们列表中的消息,因此我们知道这是此设备的新消息。 将列表限制为 20 个 ID,以免失去控制。 (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

【讨论】:

以上是关于GCM 多次推送同一消息 (PushSharp)的主要内容,如果未能解决你的问题,请参考以下文章

google gcm 没有使用 PushSharp 作为我的服务器发送消息

PushSharp 错误消息发送 IOS 推送通知

使用 PushSharp 时,GCM 通知正文始终显示为 <missing message content>

GCM 在服务器上多次收到相同的消息

推送通知在android中获得多次

Android PushSharp Notification 消息修剪