GCM 推送通知未传送到设备
GCM Push Notifications are not delivered to devices
我们(Panos 和 Rainer - 请参阅下面的评论)有一台服务器和几台 Android 设备。
我们想通过 GCM 从我们的服务器向 Android 台设备发送推送通知。
现在我们向 GCM 服务器发出 post 请求。 GCM 服务器响应是一切正常(成功==1 甚至是消息 ID)!
但是推送通知永远不会传送到设备。
如果我们使用相同的数据和 Chrome 插件 Postman - 通知会立即发送。
我们尝试了很多不同的解决方案。我们总是得到 GCM 服务器的反馈,一切正常 - 但推送通知未发送。
This 是用于 Postman 请求的数据,可以正常工作。
Rainer 已经提到我们在 Java 端尝试了几种实现,似乎我们总是能够与服务通信并收到到目前为止看起来正确的响应:
{
"multicast_id":7456542468425129822,
"success":1,
"failure":0,
"canonical_ids":0,
"results":
[{
"message_id":"0:1457548597263237%39c590d7f9fd7ecd"
}]
}
不确定我是否在正确的轨道上,但你是指下游 HTTP 消息(纯文本)吗?
尝试将以下 JSON 发送到服务(来自 Postman),这再次导致了肯定响应,但这次通知没有到达设备(只是为了说明这一点,目前有设备上没有应用程序主动侦听传入通知 -> 首先我们只想确保它们通常到达设备):
{
"data":
{
"score": "5x1",
"time": "15:10"
},
"to" : "SECRET-DEVICE-TOKEN"
}
感谢所有试图在这里提供帮助的人,但老实说,这个问题真的很令人沮丧。与似乎无法 return 有用响应的 interface\service 进行通信,以防请求包含可能最终阻止 GCM 向设备发送推送通知的恶意内容,感觉就像一个痛苦屁股。如果 Postman 也会失败我会说好吧,你不能这么傻:-)
这是我们已经使用过的一些快速但肮脏的实现。
例子
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);
}
例子
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
}
例子
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);
}
例子
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);
}
您也可以 post 您使用的 URL。有一个新的 GCM enpoint,如下所示:
https://gcm-http.googleapis.com/gcm/send
我还不确定是什么导致了您这边的问题。但是以下内容已经过测试并且可以正常工作:
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();
}
}
迈克,您的示例也适用于我们这边。在将您的实现与我们这边的实现进行比较后,我发现唯一真正的区别是使用的 URL!!
在我们的 Java 实现中使用的 URL 不知何故是 https://android.googleapis.com/gcm/send
似乎 https://gcm-http.googleapis.com/gcm/send 是正确的,顺便说一下,它也用于我们的 Postman 测试。
但是,为什么我们失败的测试中的 URL 仍然有效并且 returns 有回应!?
在 json 中将优先级设置为高解决了我的问题。
'registration_ids' => $id,
'priority' => 'high',
'data' => $load
对于我们的案例,客户端 Android 设备存在间歇性互联网连接问题,即网络中断,从而导致通知传递失败。我们使用以下 JAVA GCM 代码解决了可靠性问题:
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");
和 APNS 代码:
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);
}
此外,如果您的后端服务器时间与客户端移动应用程序时间不同,请记住考虑时区。
我们(Panos 和 Rainer - 请参阅下面的评论)有一台服务器和几台 Android 设备。
我们想通过 GCM 从我们的服务器向 Android 台设备发送推送通知。
现在我们向 GCM 服务器发出 post 请求。 GCM 服务器响应是一切正常(成功==1 甚至是消息 ID)! 但是推送通知永远不会传送到设备。
如果我们使用相同的数据和 Chrome 插件 Postman - 通知会立即发送。
我们尝试了很多不同的解决方案。我们总是得到 GCM 服务器的反馈,一切正常 - 但推送通知未发送。
This 是用于 Postman 请求的数据,可以正常工作。 Rainer 已经提到我们在 Java 端尝试了几种实现,似乎我们总是能够与服务通信并收到到目前为止看起来正确的响应:
{
"multicast_id":7456542468425129822,
"success":1,
"failure":0,
"canonical_ids":0,
"results":
[{
"message_id":"0:1457548597263237%39c590d7f9fd7ecd"
}]
}
不确定我是否在正确的轨道上,但你是指下游 HTTP 消息(纯文本)吗?
尝试将以下 JSON 发送到服务(来自 Postman),这再次导致了肯定响应,但这次通知没有到达设备(只是为了说明这一点,目前有设备上没有应用程序主动侦听传入通知 -> 首先我们只想确保它们通常到达设备):
{
"data":
{
"score": "5x1",
"time": "15:10"
},
"to" : "SECRET-DEVICE-TOKEN"
}
感谢所有试图在这里提供帮助的人,但老实说,这个问题真的很令人沮丧。与似乎无法 return 有用响应的 interface\service 进行通信,以防请求包含可能最终阻止 GCM 向设备发送推送通知的恶意内容,感觉就像一个痛苦屁股。如果 Postman 也会失败我会说好吧,你不能这么傻:-)
这是我们已经使用过的一些快速但肮脏的实现。
例子
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); }
例子
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 }
例子
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); }
例子
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); }
您也可以 post 您使用的 URL。有一个新的 GCM enpoint,如下所示:
https://gcm-http.googleapis.com/gcm/send
我还不确定是什么导致了您这边的问题。但是以下内容已经过测试并且可以正常工作:
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();
}
}
迈克,您的示例也适用于我们这边。在将您的实现与我们这边的实现进行比较后,我发现唯一真正的区别是使用的 URL!! 在我们的 Java 实现中使用的 URL 不知何故是 https://android.googleapis.com/gcm/send
似乎 https://gcm-http.googleapis.com/gcm/send 是正确的,顺便说一下,它也用于我们的 Postman 测试。
但是,为什么我们失败的测试中的 URL 仍然有效并且 returns 有回应!?
在 json 中将优先级设置为高解决了我的问题。
'registration_ids' => $id,
'priority' => 'high',
'data' => $load
对于我们的案例,客户端 Android 设备存在间歇性互联网连接问题,即网络中断,从而导致通知传递失败。我们使用以下 JAVA GCM 代码解决了可靠性问题:
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");
和 APNS 代码:
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);
}
此外,如果您的后端服务器时间与客户端移动应用程序时间不同,请记住考虑时区。