GCM:MulticastResult - 哪个结果来自哪个设备?

Posted

技术标签:

【中文标题】GCM:MulticastResult - 哪个结果来自哪个设备?【英文标题】:GCM: MulticastResult - which result is from which device? 【发布时间】:2012-07-21 16:10:16 【问题描述】:

按照GCM: Getting Started 指南的最后一部分,在收到结果后需要做一些记账。

引自指南:

现在需要解析结果并在以下情况下采取适当的措施:

如果消息已创建,但结果返回了规范的注册 ID,则需要替换当前注册 带有规范的 ID。 如果返回的错误是 NotRegistered,则需要删除该注册 ID,因为应用程序已从 设备。

这是处理这两个条件的代码 sn-p:

if (result.getMessageId() != null) 
 String canonicalRegId = result.getCanonicalRegistrationId();
 if (canonicalRegId != null) 
   // same device has more than on registration ID: update database
 
 else 
 String error = result.getErrorCodeName();
 if (error.equals(Constants.ERROR_NOT_REGISTERED)) 
   // application has been removed from device - unregister database
 

以上指南指的是单个结果,而不是多播情况。 我不确定如何处理多播情况:

    ArrayList<String> devices = new ArrayList<String>();

    for (String d : relevantDevices) 
        devices.add(d);
    

    Sender sender = new Sender(myApiKey);
    Message message = new Message.Builder().addData("hello", "world").build();
    try 
        MulticastResult result = sender.send(message, devices, 5);

        for (Result r : result.getResults()) 
            if (r.getMessageId() != null) 
                String canonicalRegId = r.getCanonicalRegistrationId();
                if (canonicalRegId != null) 
                    // same device has more than on registration ID: update database
                    // BUT WHICH DEVICE IS IT?
                
             else 
                String error = r.getErrorCodeName();
                if (error.equals(Constants.ERROR_NOT_REGISTERED)) 
                    // application has been removed from device - unregister database
                    // BUT WHICH DEVICE IS IT?
                
            
        
     catch (IOException ex) 
        Log.err(TAG, "sending message failed", ex);
    

我提交了一份设备列表,并收到了一份结果列表。 Result 对象不包含注册 id,但如果第一个已过时,则仅包含规范 id。 如果这两个列表相互关联(即保留顺序和大小),则没有记录。

我如何确定哪个结果是指哪个设备?

-- 更新

我已将解决方案的 sn-p 粘贴到下面的单独答案中

【问题讨论】:

【参考方案1】:

结果按照您发送到 GCM 服务器的 registration_id 数组的顺序排列。例如如果您的registration_ids 是:

[id1, id4, id7, id8]

那么你得到的结果数组对于 id1、id4、id7 和 id8 将具有相同的顺序。

您只需要相应地解析每个结果,例如如果第二个结果有 'message_id' 和 'registration_id' of 'id9',你知道 'id4' 现在已经过时了,应该被 id9 取代。

【讨论】:

谢谢!我刚刚在 GCM google 组 (groups.google.com/forum/#!topic/android-gcm/DCHHQwqTs8M) 中找到了这些信息。新的 API 需要时间来获得正确的文档..【参考方案2】:

为了方便读者,这里是一个处理多个设备响应的 sn-p

public void sendMessageToMultipleDevices(String key, String value, ArrayList<String> devices) 

        Sender sender = new Sender(myApiKey);
        Message message = new Message.Builder().addData(key, value).build();
        try 
            MulticastResult result = sender.send(message, devices, 5);
            MTLog.info(TAG, "result " + result.toString());


            for (int i = 0; i < result.getTotal(); i++) 
                Result r = result.getResults().get(i);

                if (r.getMessageId() != null) 
                    String canonicalRegId = r.getCanonicalRegistrationId();
                    if (canonicalRegId != null) 
                        // devices.get(i) has more than on registration ID: update database

                    
                 else 
                    String error = r.getErrorCodeName();
                    if (error.equals(Constants.ERROR_NOT_REGISTERED)) 
                        // application has been removed from devices.get(i) - unregister database
                    
                
            
         catch (IOException ex) 
            MTLog.err(TAG, "sending message failed", ex);
        
    

【讨论】:

Result 类有 3 个字段:messageId、canonicalRegistrationId 和 errorCode。所有相关案例都包含在代码 sn-p 中。 canonicalRegistrationId 是一个更新的 gcm 密钥。 devices.get(i) has more than one registration ID: update database - 在这里应该做什么?从数据库中删除 devices.get(i) 或从结果中删除具有 canonicalRegistrationId 的设备?或者检查数据库中是否存在具有 canonicalRegistrationId 的设备?如果是,则删除另一个,如果为false,则更改另一个的id? 您应该用新的 canonicalRegistrationId = new regId 替换旧 regId 的 devices.get(i)。你可能已经有了新的 regId,如果你用新的 regId 注册了同一个用户(认为它是新用户),然后尝试用旧的 id 联系到他。【参考方案3】:

此解决方案由谷歌开发者示例 GCM Demo application 完成 注意多播句柄的 asyncSend

List<GcmUsers> devices=SearchRegisterdDevicesByCourseCommand.execute(instructorId, courseId);
    String status;
    if ( devices.equals(Collections.<GcmUsers>emptyList()))     
      status = "Message ignored as there is no device registered!";
     else 
      // NOTE: check below is for demonstration purposes; a real application
      // could always send a multicast, even for just one recipient
      if (devices.size() == 1) 
        // send a single message using plain post
        GcmUsers gcmUsers = devices.get(0);
        Message message = new Message.Builder().build();
        Result result = sender.send(message, gcmUsers.getGcmRegid(), 5);
        status = "Sent message to one device: " + result;
       else 
        // send a multicast message using JSON
        // must split in chunks of 1000 devices (GCM limit)
        int total = devices.size();
        List<String> partialDevices = new ArrayList<String>(total);
        int counter = 0;
        int tasks = 0;
        for (GcmUsers device : devices) 
          counter++;
          partialDevices.add(device.getGcmRegid());
          int partialSize = partialDevices.size();
          if (partialSize == MULTICAST_SIZE || counter == total) 
            asyncSend(partialDevices);
            partialDevices.clear();
            tasks++;
          
        
        status = "Asynchronously sending " + tasks + " multicast messages to " +
            total + " devices";
      
    
    req.setAttribute(HomeServlet.ATTRIBUTE_STATUS, status.toString());






private void asyncSend(List<String> partialDevices) 
    // make a copy
    final List<String> devices = new ArrayList<String>(partialDevices);
    threadPool.execute(new Runnable() 

      public void run() 
        Message message = new Message.Builder().build();
        MulticastResult multicastResult;
        try 
          multicastResult = sender.send(message, devices, 5);
         catch (IOException e) 
          logger.log(Level.SEVERE, "Error posting messages", e);
          return;
        
        List<Result> results = multicastResult.getResults();
        // analyze the results
        for (int i = 0; i < devices.size(); i++) 
          String regId = devices.get(i);
          Result result = results.get(i);
          String messageId = result.getMessageId();
          if (messageId != null) 
            logger.fine("Succesfully sent message to device: " + regId +
                "; messageId = " + messageId);
            String canonicalRegId = result.getCanonicalRegistrationId();
            if (canonicalRegId != null) 
              // same device has more than on registration id: update it
              logger.info("canonicalRegId " + canonicalRegId);
              Datastore.updateRegistration(regId, canonicalRegId);
            
           else 
            String error = result.getErrorCodeName();
            if (error.equals(Constants.ERROR_NOT_REGISTERED)) 
              // application has been removed from device - unregister it
              logger.info("Unregistered device: " + regId);
              Datastore.unregister(regId);
             else 
              logger.severe("Error sending message to " + regId + ": " + error);
            
          
        
      );
  

【讨论】:

您链接到的示例应用程序中有一条注释:“本文档中的信息已被 GCM 服务器和 GCM 客户端取代。请使用 GoogleCloudMessaging API 而不是 GCM 客户端帮助程序库。GCM服务器帮助程序库仍然有效。”。你的答案是最新的吗? 它的 2 周更新看起来谷歌已经更新了库并且演示还没有更新:)

以上是关于GCM:MulticastResult - 哪个结果来自哪个设备?的主要内容,如果未能解决你的问题,请参考以下文章

某些设备在 android 中未收到推送通知

哪个版本的gcm服务器用于gcm -fcm迁移

GCM Push Server 端,使用哪个 API Key?

GCM 服务器在哪个时间频率刷新注册 ID 以及如何在我的手机中获取 regId 更改事件?

Android - 我如何发送 GCM 推送通知,其中包含要加载哪个活动的说明?

在哪个事件中,我可以使用 PushSharp 获取 GCM 响应以向 Android 设备发送通知?