GCM push message encoding

I am trying to send push notifications using the following code:

Message message = new Message.Builder().addData("appName", appData.name) .addData("message", pushData.message).build(); 

On the receiving side, my code is:

 String message = intent.getStringExtra("message"); 

When the message is in English, Latin encoding, everything works. However, when I try to use other languages ​​or the ç symbol, they appear as question marks or are removed from the string.

Note: it is encoded in utf-8

+7
source share
5 answers

Break with the debugger and view the bytes of the message that you think you send

0
source

Java server

 Message messagePush = new Message.Builder().addData("message", URLEncoder.encode("your message éèçà", "UTF-8"))) 

Android app

 String message = URLDecoder.decode(intent.getStringExtra("message"), "UTF-8"); 
+9
source

I had the same problem. Non-character ASCII characters that were corrupted upon receipt on the Android client. I personally think this is a problem in implementing the GCM server library.

In the Android GCM library, I see a method:

 com.google.android.gcm.server.Sender.sendNoRetry(Message, List<String>) 

This method performs the following

 HttpURLConnection conn = post(GCM_SEND_ENDPOINT, "application/json", requestBody) 

They should at least specify "application / json; charset = utf-8 " either regardless of which encoding they used or even better, but forced it to use UTF-8. Isn't that a BIG problem?

Digging even deeper, I find a method:

 com.google.android.gcm.server.Sender.post(String, String, String) 

which does:

 byte[] bytes = body.getBytes() 

Why do they use the default encoding for the platform? Moreover, it is hardly compatible with the default encoding for devices.

Work around

Pass the following property as the JVM argument " -Dfile.encoding = UTF-8 ". This instructs Java to use UTF-8 as the default encoding for the platform when performing actions such as "blah",. GetBytes (). This is bad practice, but what can you do when it is some other library?

+2
source

I had a similar problem with the gcm-server library. My workaround used a custom sender to override the post method and use UTF8 as the encoding in the getBytes() call. He works in Google App Engine.

Custom sender class code:

 import java.io.Closeable; import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; import java.util.logging.Level; import com.google.android.gcm.server.Sender; /** * Workaround to avoid issue #13 of gcm-server * @see https://code.google.com/p/gcm/issues/detail?id=13&q=encoding * * @author rbarriuso /at/ tribalyte.com * */ public class Utf8Sender extends Sender { private final String key; public Utf8Sender(String key) { super(key); this.key = key; } @Override protected HttpURLConnection post(String url, String contentType, String body) throws IOException { if (url == null || body == null) { throw new IllegalArgumentException("arguments cannot be null"); } if (!url.startsWith("https://")) { logger.warning("URL does not use https: " + url); } logger.fine("Utf8Sender Sending POST to " + url); logger.finest("POST body: " + body); byte[] bytes = body.getBytes(UTF8); HttpURLConnection conn = getConnection(url); conn.setDoOutput(true); conn.setUseCaches(false); conn.setFixedLengthStreamingMode(bytes.length); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", contentType); conn.setRequestProperty("Authorization", "key=" + key); OutputStream out = conn.getOutputStream(); try { out.write(bytes); } finally { close(out); } return conn; } private static void close(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (IOException e) { // ignore error logger.log(Level.FINEST, "IOException closing stream", e); } } } } 
+2
source

These were good solutions, but they didn’t help me because I used text messages to send notifications. By this

The HTTP header should contain the following headers: Authorization: key = YOUR_API_KEY Content-Type: application / json for JSON; application / x-www-form-urlencoded; charset = UTF-8 for plain text. If the Content-Type is omitted, the format is considered plain text.

However, since I am using cloud endpoints, and my application (already out of the game) expects json, formatting the request as plain text was not viable. The solution was to ignore the document above, and in my backend, format the header of the http request as such:

  connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); 

Like magic, all of a sudden all special characters (read: Japanese) pass into my application without any front end changes. My full http zip code is below ( where payload = Cloud endpoint model object, converted to json<String> via Gson):

  try { URL url = new URL("https://gcm-http.googleapis.com/gcm/send"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); connection.setRequestProperty("Authorization", "key=" + API_KEY); connection.setRequestMethod("POST"); byte[] bytes=payload.getBytes("UTF-8"); OutputStream out = connection.getOutputStream(); try { out.write(bytes); } finally { out.close(); } if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { // OK log.warning("OK"); } else { // Server returned HTTP error code. log.warning("some error "+connection.getResponseCode()); } } catch (MalformedURLException e) { // ... } 
+2
source

All Articles