2
votes

We (Panos and Rainer - see the comments down) have a server and several Android devices.

We want to send push notifications from our server via GCM to the Android devices.

Now we make a post request to the GCM server. The GCM server response is that all is fine (success==1 and even the message-id)! BUT the push notification(s) are never delivered to the devices.

If we use the same data and the Chrome addon Postman - the notifications are delivered immediately.

We tried all lot of different solutions. We get always the feedback of the GCM server that all is ok - but the push notifications aren't send.

We also tried this one: https://github.com/googlesamples/google-services/blob/master/android/gcm/gcmsender/src/main/java/gcm/play/android/samples/com/gcmsender/GcmSender.java

7
Can you share some code and some more information about your postman request?Sam Stern
Is Google play services installed on the device? Does your firewall allow idle connections over tcp 5228-5230? It can take up to 15 minutes for the gcm service to re-connect if the connection is dropped.Hugh Jeffner
All is installed. Ports are open. We tried it within wifi and cellular. We get push notifications when we send it via postman.RaLA
If you are receiving the notifications via Postman, then all is well on the device side. Could you add the code you are using to send your request that is not being received by your device? My guess would be that there is something different about the HTTP request from your code.Arthur Thompson

7 Answers

0
votes

You might also post the URL you use. There is a new GCM enpoint which looks like the following:

https://gcm-http.googleapis.com/gcm/send

I am not yet sure what's causing the issues on your side. But the following is tested and working:

public class Main {

    public static void main(String[] args) {
    // write your code here

        try {

            String url = "https://gcm-http.googleapis.com/gcm/send";

            URL obj = new URL(url);
            HttpsURLConnectionImpl conn = (HttpsURLConnectionImpl) obj.openConnection();


            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);

            conn.setRequestMethod("POST");
            conn.setRequestProperty ("Authorization", "key=***");

            String title = "Short title";
            String body = "A body :D";
            String token = "****";
            String data =  "{ \"notification\": { \"title\": \"" + title +"\", \"body\": \"" + body + "\" }, \"to\" : \"" + token + "\", \"priority\" : \"high\" }";
            OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
            out.write(data);
            out.close();

            String text = getText(new InputStreamReader(conn.getInputStream()));
            System.out.println(text);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String getText(InputStreamReader in) throws IOException {
        StringBuilder sb=new StringBuilder();
        BufferedReader br = new BufferedReader(in);
        String read;
        while((read=br.readLine()) != null) {
            sb.append(read);
        }
        br.close();
        return sb.toString();
    }
}
0
votes

This is the data used for the Postman request which is working without any problem. Rainer already mentioned that we tried several implementations on the Java side and it seems that we are always able to communicate with the service and receive a response which seems to look correct so far:

{
    "multicast_id":7456542468425129822,
    "success":1,
    "failure":0,
    "canonical_ids":0,
    "results":
    [{
        "message_id":"0:1457548597263237%39c590d7f9fd7ecd"
    }]
} 
0
votes

Not sure if I'm on the right track but do you mean downstream HTTP messages (plain text)?

Tried to send the following JSON to the service (from Postman) which results again in a positive response but this time the notification did not reach the device (just to make that clear, at the moment there is no app on the device listening actively for incoming notifications -> first of all we just want to ensure that they generally arrive on the device):

{ 
   "data": 
   {
      "score": "5x1",
      "time": "15:10"
   },
   "to" : "SECRET-DEVICE-TOKEN"
}
0
votes

Thanks to all of you trying to help here but to be honest, this issue is really frustrating. Communicating with an interface\service which seems not to be able to return a useful response in case the request contains maybe evil stuff which will finally prevent GCM from sending the push notification to the device, feels like a pain in the ass. If Postman would also fail I would say ok, you can not be so stupid :-)

Here are some quick'n dirty implementations we have already used.

  1. Example

        try 
        {
           URL url = new URL(apiUrl);
           HttpsURLConnection conn = (HttpsURLConnection);//also tried HttpURLConnection
           url.openConnection();
           conn.setDoOutput(true);
           conn.setRequestMethod("POST");
           conn.setRequestProperty("Content-Type", "application/json");
           conn.setRequestProperty("Authorization", "key="+apiKey);
    
           conn.setDoOutput(true);
    
           String json = "{\"priority\":\"high\",\"notification\":{\"title\":\"Some title\",\"text\":\"Some text\"},\"to\":\""+deviceToken+"\"}";
    
           OutputStream os = conn.getOutputStream();
           os.write(json.getBytes());
           os.flush();
       }
       catch(Exception exc)
       {
         System.out.println("Error while trying to send push notification: "+exc);
       }
    
  2. Example

    HttpClient httpClient = HttpClientBuilder.create().build(); 
    
    try 
    {
        HttpPost request = new HttpPost(apiUrl);
        StringEntity params =new StringEntity("{\"priority\":\"high\",\"notification\":{\title\":\"Some title\",\"text\":\"Some text\"},\"to\":\""+deviceToken+"\"}");
        request.addHeader("Content-Type", "application/json");
        request.addHeader("Authorization", "key="+apiKey);
        request.setEntity(params);
        HttpResponse response = httpClient.execute(request);
    
        // check response
        System.out.println(response.getStatusLine().toString());
    }catch (Exception exc) {
        System.out.println("Error while trying to send push notification: "+exc);
    } finally {
        httpClient.getConnectionManager().shutdown(); //Deprecated
    }
    
  3. Example

    try
    {
        String charset = "UTF-8"; 
        URLConnection connection = new URL(apiUrl).openConnection();
        connection.setDoOutput(true);
        connection.setRequestProperty("Accept-Charset", charset);
        connection.setRequestProperty("Content-Type", "application/json;charset=" + charset);
        connection.setRequestProperty("Authorization", "key="+apiKey);
    
        String param = "{\"priority\":\"high\",\"notification\":{\"title\":\"Some title\",\"text\":\"Some text\"},\"to\":\""+deviceToken+"\"}";
        try (OutputStream output = connection.getOutputStream()) 
        {
            output.write(param.getBytes(charset));
        }
    
        InputStream response = connection.getInputStream();
    }
    catch(Exception exc)
    {
        System.out.println("Error while trying to send push notification: "+exc);
    }
    
  4. Example

    try 
    {
        // prepare JSON
        JSONObject jGcmData = new JSONObject();
        JSONObject jData = new JSONObject();
    
        jData.put("message", "{ \"data\": {\"score\": \"5x1\",\"time\": \"15:10\"},\"to\" : \""+deviceToken+"\"}");
    
        jGcmData.put("to", deviceToken);
    
        jGcmData.put("data", jData);
    
        // Create connection to send GCM Message request.
        URL url = new URL("https://android.googleapis.com/gcm/send");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestProperty("Authorization", "key=" + apiKey);
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);
    
        // Send GCM message content.
        OutputStream outputStream = conn.getOutputStream();
        outputStream.write(jGcmData.toString().getBytes());
    
        // Read GCM response.
        InputStream inputStream = conn.getInputStream();
        String resp = IOUtils.toString(inputStream);
        System.out.println(resp);
     } catch (IOException e) {
        System.out.println("Unable to send GCM message. "+e);
    }
    
0
votes

Mike, with your example it's working also on our side. After comparing your implementation with the on eon our side, the only real difference I found is the used URL!! Somehow the URL used in our Java implementation was https://android.googleapis.com/gcm/send

Seems that https://gcm-http.googleapis.com/gcm/send is the right one which by the way was also used for our Postman tests.

But why on hell is the URL from our failed tests still somehowe valid and returns a response!?

0
votes

Setting the priority to high in the json resolved the issue for me.

'registration_ids' => $id,
'priority' => 'high',
'data' => $load
0
votes

For our case, the clients Android devices had intermittent internet connection issue, that is, network dropouts thus causing notification delivery failed. We resolved the reliability issue with the following JAVA GCM code:

gcmPayload.setTime_to_live(messageExpiryTime); //in seconds. Set notification message expiry to give user time to receive it in case they have intermittent internet connection, or phone was off
gcmPayload.setPriority("high");

and APNS code:

ApnsService apnsService = APNS.newService().withCert(certificateStream, configurations.getApnPassword()).withProductionDestination().build();
PayloadBuilder payloadBuilder = APNS.newPayload();
...
payloadBuilder.instantDeliveryOrSilentNotification(); //same as content-available=true
String payload = payloadBuilder.build();

Integer now =  (int)(new Date().getTime()/1000);
//use EnhancedApnsNotification to set message expiry time
for(String deviceToken : deviceTokens) {
    EnhancedApnsNotification notification = new EnhancedApnsNotification(EnhancedApnsNotification.INCREMENT_ID() /* Next ID */,
        now + messageExpiryTime /* Expiry time in seconds */,
        deviceToken /* Device Token */,
        payload);
        apnsService.push(notification);
}

Also, remember to consider time zone if your backend server time is different to the client mobile app time.