Серверная часть App Engine с Google Cloud Messaging, отправляющая сообщения более чем 1000 пользователям

Я хочу отправить сообщение (например, доступно обновление) всем пользователям (~ 15 000). Я внедрил серверную часть App Engine с Google Cloud Messaging для отправки сообщений.

Я тестировал на 2 устройствах. Получил сообщение на обоих. Но, как сказано в документах Google, "GCM поддерживает до 1000 получателей для одного сообщения".

Мой вопрос: как отправить одно и то же сообщение оставшимся 14 000 пользователей в моем случае? Или приведенный ниже код позаботится об этом?

Ниже приведен код, который отправляет сообщение

import com.google.android.gcm.server.Constants;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;
import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiNamespace;

import java.io.IOException;
import java.util.List;
import java.util.logging.Logger;

import javax.inject.Named;

import static com.example.shani.myapplication.backend.OfyService.ofy;

/**
 * An endpoint to send messages to devices registered with the backend
 * <p/>
 * For more information, see
 * https://developers.google.com/appengine/docs/java/endpoints/
 * <p/>
 * NOTE: This endpoint does not use any form of authorization or
 * authentication! If this app is deployed, anyone can access this endpoint! If
 * you'd like to add authentication, take a look at the documentation.
 */
@Api(name = "messaging", version = "v1", namespace = @ApiNamespace(ownerDomain = "backend.myapplication.shani.example.com", ownerName = "backend.myapplication.shani.example.com", packagePath = ""))
public class MessagingEndpoint {
    private static final Logger log = Logger.getLogger(MessagingEndpoint.class.getName());

    /**
     * Api Keys can be obtained from the google cloud console
     */
    private static final String API_KEY = System.getProperty("gcm.api.key");

    /**
     * Send to the first 10 devices (You can modify this to send to any number of devices or a specific device)
     *
     * @param message The message to send
     */
    public void sendMessage(@Named("message") String message) throws IOException {
        if (message == null || message.trim().length() == 0) {
            log.warning("Not sending message because it is empty");
            return;
        }
        // crop longer messages
        if (message.length() > 1000) {
            message = message.substring(0, 1000) + "[...]";
        }
        Sender sender = new Sender(API_KEY);

         Message msg = new Message.Builder().addData("message", message).build();

        List<RegistrationRecord> records = ofy().load().type(RegistrationRecord.class).limit(1000).list();
        for (RegistrationRecord record : records) {
            Result result = sender.send(msg, record.getRegId(), 5);
            if (result.getMessageId() != null) {
                log.info("Message sent to " + record.getRegId());
                String canonicalRegId = result.getCanonicalRegistrationId();
                if (canonicalRegId != null) {
                    // if the regId changed, we have to update the datastore
                    log.info("Registration Id changed for " + record.getRegId() + " updating to " + canonicalRegId);
                    record.setRegId(canonicalRegId);
                    ofy().save().entity(record).now();
                }
            } else {
                String error = result.getErrorCodeName();
                if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
                    log.warning("Registration Id " + record.getRegId() + " no longer registered with GCM, removing from datastore");
                    // if the device is no longer registered with Gcm, remove it from the datastore
                    ofy().delete().entity(record).now();
                } else {
                    log.warning("Error when sending message : " + error);
                }
            }
        }
    }
}

Я знаю, что есть похожие вопросы, но я использую язык Java. Я нашел вопросы, которые используют язык php в бэкэнде. так мне не поможет!

  1. Google Cloud Messaging: отправить сообщение всем пользователям
  2. Отправка push-уведомлений на нескольких устройствах

Есть ли кто-нибудь, кто успешно внедрил язык JAVA App Engine + Google Cloud Messaging?

В приведенной ниже строке кода, если я заменю 1000 на 15 000, решит ли это мою проблему?

List<RegistrationRecord> records = ofy().load().type(RegistrationRecord.class).limit(1000).list();

Пожалуйста, помогите как можно скорее. И очень извините за мой английский .. Если кому-то нужны другие подробности, вы можете спросить.

Спасибо за ваше время.


person Programmer    schedule 18.04.2015    source источник
comment
что происходит, когда вы запускаете код, который, как вы говорите, может работать?   -  person Paul Collingwood    schedule 18.04.2015
comment
@PaulCollingwood Когда я запускаю клиентский код на 2 устройствах, все получают регистрационный идентификатор, затем я отправляю сообщения с appspot.com, все устройства получают сообщения. Спасибо.   -  person Programmer    schedule 18.04.2015
comment
Проверьте [Мой вопрос/ответ] [1]. Я сделал это таким образом, но требует некоторого тестирования [1]: stackoverflow.com/questions/29934331/   -  person George2456    schedule 29.04.2015


Ответы (2)


Несколько соображений,

1) Отправка уведомлений большому количеству пользователей может занять значительное время. Рассмотрите возможность использования очередей задач. поставить в очередь эту работу, которая должна быть выполнена «в автономном режиме» за пределами 60-секундного ограничения.

2) Теперь, что касается лимита GCM, если вам нужны все ваши пользователи, но GCM позволяет вам 1000 за раз, просто разделите их на пакеты по 1000 и отправьте каждому пакету сообщение отдельно.

Если вы объедините обе рекомендации, у вас должен быть достаточно масштабируемый процесс, в котором вы запрашиваете всех своих пользователей в 1 запросе, разделяете этот список и просто отправляете сообщение этим пользователям по 1000 за раз.

person jirungaray    schedule 18.04.2015
comment
Привет jirungaray, спасибо за ответ. Я согласен с вашими соображениями. Если вы можете дать мне пример кода, это будет большим подспорьем. - person Programmer; 18.04.2015
comment
Есть ли у вас более простое решение для пакетных запросов на 1000 пользователей? Я не знаю очереди задач. - person Programmer; 18.04.2015
comment
Я могу придумать множество решений, ни одно из которых не проще, чем использование очередей. Очереди задач — это базовый сервис для GAE, и вы обязательно должны прочитать о них по ссылке, которую я предоставил. Кроме того, если вы не прибегаете к очередям или внутренним процессам, ваше приложение не будет работать за пределами заданного количества пользователей. У вас уже есть код, вам просто нужно переместить отправляющую часть в другой сервлет и установить для нее очередь. В документации показано, как это сделать за 5 минут. - person jirungaray; 18.04.2015

Расширение ответа @jirungaray ниже представляет собой код для отправки сообщений GCM всем зарегистрированным пользователям,

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

public class GCM {
    private final static Logger LOGGER = Logger.getLogger(GCM.class.getName());
    private static final String API_KEY = ConstantUtil.GCM_API_KEY;
    public static void doSendViaGcm(List<String> tocken,String message) throws IOException {
        Sender sender = new Sender(API_KEY);
    // Trim message if needed.
    if (message.length() > 1000) {
      message = message.substring(0, 1000) + "[...]";
     }
     Message msg = new Message.Builder().addData("message", message).build();
    try{
    MulticastResult result = sender.send(msg, tocken, 5);
    }catch(Exception ex){
    LOGGER.severe("error is"+ex.getMessage());
    ex.printStackTrace();
    }
}

}

В приведенном выше фрагменте кода API_KEY можно получить из проекта консоли Google, здесь я предполагаю, что вы уже создали один проект консоли Google и включите API GCM,

вы можете сгенерировать API_KEY следующим образом

your_google_console_project >> Учетные данные >> Создать новый ключ >> Ключ сервера >> введите IP-адрес, которому вы хотите разрешить доступ к API GCM [я использовал 0.0.0.0/0]

Теперь doSendViaGcm (токен списка, строковое сообщение) класса GCM выполняет задачу отправки сообщений на все зарегистрированные мобильные устройства Android.

здесь List<String> token is array-list of all device token, по которому будут доставляться сообщения, помните, что это list size не должно быть больше than 1000, иначе HTTP-вызов завершится ошибкой.

надеюсь, это поможет вам спасибо

person Dev    schedule 20.04.2015
comment
Привет Дев Спасибо за ваш вклад. Извините, но я не понимаю, что эта часть хранит эти токены устройств в базе данных. Я не писал специальный код для хранения токена устройства. Как я вижу, в коде сервера App Engine есть файл RegistrationEndpoint.java, состоящий из registerDevice(), listDevice(). Я думаю, что эти методы уже хранят регистрационные идентификаторы устройств. Нужно ли мне писать код для того же? Пожалуйста, развейте мои сомнения. - person Programmer; 21.04.2015
comment
Похоже, вы используете облачную конечную точку, в таком случае listDevice() должен работать нормально, но в таком случае вам нужно извлечь строку токена из объекта устройства. Позвольте мне спросить вас, откуда вы будете отправлять сообщения GCM с самого андроида или из движка приложения. приложение?? - person Dev; 21.04.2015
comment
Я использую сервер HTTP-соединений, и для этого я использую серверную часть Google App Engine. Я отправляю сообщение из project_id.appspot.com/_ah/api/explorer. - person Programmer; 21.04.2015
comment
поэтому в основном вы используете шаблон по умолчанию из project_id.appspot.com/_ah/api/explorer для отправки push-уведомления GCM клиенту Android, я думаю, вам следует создать одну конечную точку и реализовать один метод, который вызывает listDevices() в таблице устройств, извлекает токен из объекта Device и отправлять сообщения GCM [бизнес-логика], вы можете вызвать эту конечную точку с одной из веб-страниц вашего приложения - person Dev; 21.04.2015
comment
Извините, что спрашиваю вас неоднократно, но я очень новичок в App-Engine, на самом деле в веб-приложениях. На самом деле мое приложение работает в автономном режиме (поэтому у меня нет веб-страниц), теперь, когда я хочу реализовать в нем функцию push-уведомлений Google. Я выполняю шаги cloud.google.com/mobile/messaging. Не могли бы вы просмотреть код сервера github.com/GoogleCloudPlatform/gradle- appengine-шаблоны/дерево/. Пожалуйста, предложите мне изменения, которые мне нужны. Большое спасибо за поддержку. - person Programmer; 21.04.2015
comment
Я не так хорошо знаком с конечной точкой, но я использую приведенный выше фрагмент кода с проектом Appengine, используя serverlt, перейдите по этой ссылке cloud.google.com/appengine/docs/java/gettingstarted/ui_and_code для получения дополнительной информации. - person Dev; 22.04.2015