简体   繁体   中英

GCM push message encoding

I am trying to send push notifications using 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 charset, everything works. However, when I try other languages or the character ç, they arrive as question marks or are deleted from the string.

Note: it's encoded in utf-8

Java server

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

Android application

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

I was having the same issue. Non ASCII characters where corrupted when received on the Android client. I personally believe this is a problem within the Google GCM server library implementation.

In the Android GCM library I see the method:

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

That method does the following

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

They should atleast specify "application/json; charset=utf-8 " or whatever encoding they used or better yet force it to UTF-8. Isn't this is a BIG problem?

Digging even deeper I find the method:

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

which does:

byte[] bytes = body.getBytes()

Why do they use the platform default charset? Especially since it is not likely to align with the devices default charset.

Work Around

Pass the following property as an argument to the JVM " -Dfile.encoding=UTF-8 " This instructs Java to use UTF-8 as the platform default charset when doing things like "blah".getBytes(). This is bad practice but what can you do when it is someone else's library?

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

The code of the custom sender class:

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

}

These were some good solutions, however they didnt help me because I was using topic messaging to send notifications. As per this

The HTTP header must 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 Content-Type is omitted, the format is assumed to be plain text.

However, because I am using cloud endpoints and my app (already out in the wild) is expecting json, formatting the request in plain text wasnt viable. The solution was to ignore the document above, and in my backend, format the http request header as such:

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

Like magic, suddenly all special characters (read: Japanese) is going through to my application with no front end changes being made. My complete http post 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) {
        // ...
    }

断开调试器并查看您认为正在发送的消息的字节

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM