Кодирование сообщения GCM push

Я пытаюсь отправить push-уведомления, используя следующий код:

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

На принимающей стороне мой код:

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

Когда сообщение на английском языке, латинская кодировка, все работает. Однако, когда я пытаюсь использовать другие языки или символ ç, они появляются как вопросительные знаки или удаляются из строки.

Примечание: оно закодировано в utf-8

Перерыв с отладчиком и просмотр байтов сообщения, которое, по вашему мнению, вы отправляете

Сервер Java

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

Android-приложение

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

У меня была такая же проблема. Non ASCII-символы, которые повреждены при получении на клиенте Android. Я лично считаю, что это проблема в реализации библиотеки сервера GCM.

В библиотеке Android GCM я вижу метод:

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

Этот метод делает следующее

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

Они должны, по крайней мере, указать «application / json; charset = utf-8 » или другое кодирование, которое они использовали или еще лучше, но вынуждают его использовать UTF-8. Разве это не БОЛЬШАЯ проблема?

Выкапывая еще глубже, я нахожу метод:

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

Который делает:

 byte[] bytes = body.getBytes() 

Почему они используют кодировку по умолчанию для платформы? Тем более, что он вряд ли совместим с кодировкой по умолчанию для устройств.

Работа вокруг

Передайте следующее свойство в качестве аргумента в JVM « -Dfile.encoding = UTF-8 ». Это дает указание Java использовать UTF-8 в качестве кодировки по умолчанию для платформы при выполнении таких вещей, как «blah» .getBytes (). Это плохая практика, но что вы можете сделать, когда это чужая библиотека?

У меня была аналогичная проблема с библиотекой gcm-server. В моем обходном пути использовался пользовательский отправитель для переопределения метода post и использования UTF8 в качестве кодировки в getBytes() . Он работает в Google App Engine.

Код пользовательского класса отправителя:

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

Это были хорошие решения, однако они мне не помогли, потому что я использовал текстовые сообщения для отправки уведомлений. В соответствии с этим

Заголовок HTTP должен содержать следующие заголовки: Авторизация: key = YOUR_API_KEY Content-Type: application / json для JSON; Application / x-www-form-urlencoded; charset = UTF-8 для обычного текста. Если Content-Type опущен, формат считается простым текстом.

Тем не менее, поскольку я использую конечные точки для облаков, и мое приложение (уже вне игры) ожидает json, форматирование запроса в виде простого текста не было жизнеспособным. Решение заключалось в том, чтобы игнорировать вышеприведенный документ и в моем бэкэнде форматировать заголовок http-запроса как таковой:

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

Как и магия, внезапно все специальные символы (читай: японцы) проходят в мое приложение без каких-либо изменений переднего конца. Мой полный почтовый индекс http ниже ( 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) { // ... } 
Intereting Posts
Использование ThreadPoolExecutor и AsyncTask Как установить TimeZone в android Как использовать onSaveInstanceState () и onRestoreInstanceState ()? Android – Как разрешить только определенное количество знаков после запятой Загрузите видео на Youtube через студию Android Ориентировочное расположение андроидов ниже 2 элементов Android – Убейте все действия при выходе из системы GetExternalFilesDir () возвращает значение null (а не разрешение) Можем ли мы публиковать в Google плюс приложение для Android? Анимация пользовательского диалога программно Расширяемое уведомление Firebase Показать изображение, когда приложение находится в фоновом режиме Как изменить цвет кнопки в Android при нажатии? Android 2.3 Hebrew шрифты в веб-обзоре Android ScrollView (прокручивается как по горизонтали, так и по вертикали плавно), на которых содержимое может быть добавлено программно и масштабируется при нажатии Переопределить функцию кнопки громкости по умолчанию в глобальном масштабе