GCM:多播结果 - 哪个设备的结果是哪个?

31

GCM:入门指南的最后一节中,接收结果后需要进行一些记录工作。

引用指南中的内容:

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

  • 如果消息已创建但结果返回一个规范化的注册ID,则需要使用规范化的注册ID替换当前注册ID。
  • 如果返回的错误是NotRegistered,则需要删除该注册ID,因为应用程序已从设备中卸载。

这里是处理这两种情况的代码片段:

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);
    }
我提交了一个设备列表,并收到了结果列表。 结果对象不包含注册ID,只包含第一个ID过时时的规范化ID。 未说明这两个列表是否相关(例如,是否保留顺序和大小)。
我如何确定哪个结果与哪个设备相关?
-- 更新
我在下面单独的答案中粘贴了解决方案的片段。
3个回答

21

结果的顺序与您发送到 GCM 服务器的 registration_id 数组的顺序相同。例如,如果您的 registration_ids 如下:

[id1, id4, id7, id8]

那么你得到的结果数组将会与id1、id4、id7和id8的顺序相同。

你只需要相应地解析每个结果,例如,如果第二个结果具有'id9'的'message_id'和'registration_id',那么你就知道'id4'现在已经过时,应该被'id9'替换。


谢谢!我刚在GCM Google小组(https://groups.google.com/forum/#!topic/android-gcm/DCHHQwqTs8M)中找到了这些信息。新API需要一定时间才能得到适当的文档.. - Amir Uval

5
为了方便读者,这里有一段处理多个设备响应的代码片段。
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。代码片段中涵盖了所有相关情况。canonicalRegistrationId是一个更新的GCM密钥。 - Amir Uval
devices.get(i)有多个注册ID:更新数据库 - 在这里应该怎么做?从数据库中删除devices.get(i)还是从结果中删除具有canonicalRegistrationId的设备?或者检查数据库中是否存在具有canonicalRegistrationId的设备?如果是,则删除另一个,如果为假,则更改另一个的ID。 - Konsumierer
你应该用新的canonicalRegistrationId = new regId替换devices.get(i)这个旧的regId。如果你使用新的regId注册了同一个用户(认为它是一个新用户),然后尝试使用旧的id联系他,那么你可能已经有了新的regId。 - Amir Uval

3

这个解决方案是通过Google开发者示例 GCM演示应用程序完成的。 请注意,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服务器帮助库仍然有效。” 您的答案是否最新? - Amir Uval
两周过去了,看起来谷歌已经更新了这个库,但演示还没有更新 :) - shareef

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接