0

I want to send a message (e.g. Update available) to all users(~15,000). I have implemented App Engine Backend with Google Cloud Messaging to send message.

I have tested on 2 devices. Got message on both. But as google docs says "GCM is support for up to 1,000 recipients for a single message."

My question is how to send same message to remaining 14,000 users in my case? Or the code below will take care of it?

Below is the code which sends message

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);
                }
            }
        }
    }
}

I know there are simillar questions but I am using Java language. I found questions which uses php language at backend. so not helpful to me!

  1. Google Cloud Messaging: Send message to "all" users
  2. Sending Push Notification on multiple devices

Is there anyone who has successfully implemented App Engine+Google Cloud Messaging JAVA language?

In the below code line if I replace 1000 with 15,000 Will it solve my problem?

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

Please please help as soon as possible. And very sorry for my English.. If anyone need other details you are welcome to ask.

Thanks for your time.

Community
  • 1
  • 1
Programmer
  • 878
  • 2
  • 11
  • 24
  • what happens when you run the code you say might work then? – Paul Collingwood Apr 18 '15 at 11:24
  • @PaulCollingwood When I run client code on 2 devices all got reg id then i sent messages from appspot.com all devices got message. Thanks. – Programmer Apr 18 '15 at 12:13
  • Check [My Question/Answer][1] I did it that way, needs some testing though [1]: http://stackoverflow.com/questions/29934331/push-notifications-for-1000-devices-through-gcm-serverjava/29935914#29935914 – George2456 Apr 29 '15 at 11:13

2 Answers2

1

A few considerations,

1) Sending notifications to a possibly huge number of users might take significant time, consider using Task Queues to queue that work to be done "offline" outside the 60 sec limit.

2) Now as for the GCM limit, if you need to all your users but GCM allow you 1000 at a time just split them in batches of 1000 and send every batch a message separately.

If you combine both recommendations you should have a fairly scalable process where you query for all your users in 1 request , split that list and just queue sending the message to those users 1000 at a time.

jirungaray
  • 1,674
  • 1
  • 11
  • 18
  • Hi jirungaray , Thanks for answer. I am agree with your considerations. If you can give me sample code then it will be a great help. – Programmer Apr 18 '15 at 13:34
  • Do you have any simpler solution to batch requests into 1000 users? I dont know Task Queues. – Programmer Apr 18 '15 at 14:23
  • I can think of plenty of solutions, none simpler that using Queues. Task queues are a basic service for GAE and you should definitely read about them in the link i provided. Also if you dont resort to queues or backend processes your App will not work beyond a given amount of users. You already have the code, you just need to move the sending part into a different servlet and set a queue for it. The docs show you how to get that done in 5 min. – jirungaray Apr 18 '15 at 14:33
1

Extension to the @jirungaray answer below is code for sending GCM messages to all registered users,

Here I assume that from android you are registering each mobile-devices for GCM services and storing those device tokens in database.

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();
    }
}

}

In above code snippet API_KEY can be obtain from google console project ,here I assume that you have already created one google console project and enable GCM api,

you can generate API_KEY as follows

your_google_console_project>> Credentials>> Create New Key >> Server key >> enter ip address Which you want to allow access to GCM api[i used 0.0.0.0/0]

Now doSendViaGcm(List tocken,String message) of GCM class performs task of sending messages to all register android mobile devices

here List<String> token is array-list of all device token on which messages will be delivered ,remember this list size should not more than 1000 or else http call will fail.

hope this will help you thanks

Dev
  • 2,326
  • 24
  • 45
  • Hi Dev Thanks for your input. Sorry but I dont understand this part "storing those device tokens in database." I haven't written specific code for storing the device tocken. As I can see in App Engine Server code there is RegistrationEndpoint.java file consist of registerDevice(),listDevice(). I think these methods already storing device reg ids. Do I need to write a code for the same? Please clarify my doubt. – Programmer Apr 21 '15 at 11:29
  • It seem you are using cloud endpoint in such case listDevice() should just work fine but in such case you need to extract token string from Device Object .Let me ask you from where you will send GCM messages from android it self or from app engine app?? – Dev Apr 21 '15 at 11:39
  • I am using HTTP connection server and for that I am using Google App Engine Backend. I am sending message from project_id.appspot.com/_ah/api/explorer. – Programmer Apr 21 '15 at 11:43
  • 1
    so basically you are using default template from project_id.appspot.com/_ah/api/explorer to send GCM push notification to android client,I think you should create one endpoint and implement one method which call listDevices() on Device table ,extract token from Device object and send GCM messages [business logic] you might want to call this endpoint from one of the web pages of your application – Dev Apr 21 '15 at 12:36
  • Sorry to asking you repeatedly but I am very new to App-Engine in fact to web applications. Actually my app works offline (so dont have any web pages), now that I want to implement Google's push notification feature in it. I am following https://cloud.google.com/mobile/messaging/ steps. Can you please go through the server code https://github.com/GoogleCloudPlatform/gradle-appengine-templates/tree/master/GcmEndpoints. Please suggest me the changes I need to require. Thank you very much for support. – Programmer Apr 21 '15 at 12:44
  • I am not so familiar with End point but i am using above code snippet with Appengine project using servelt refer this link https://cloud.google.com/appengine/docs/java/gettingstarted/ui_and_code for more information – Dev Apr 22 '15 at 18:50