【问题标题】:Making GCM work for iOS device in the background让 GCM 在后台为 iOS 设备工作
【发布时间】:2015-09-15 13:15:29
【问题描述】:

我正在尝试将 GCM 用于 IOS 和 Android 客户端。当应用程序在前台时,它似乎可以在 IOS 上正常工作,但是,当应用程序在后台时,通知中心不会收到消息并且didReceiveRemoteNotification with completionHandler 不会被调用。

我发现一个问题是从 GCM 到 APNS 的消息格式错误。也就是说,它看起来是这样的:

[消息:新消息,collapse_key:do_not_collapse,来自:**************] 虽然,IOS 推送通知应该在通知中有aps 键,对吗?以及 content-available 设置为 1。例如:

{ “aps”:{ “内容可用”:1 }, “数据 ID”:345 }

顺便说一句,前台应用程序无论如何都会收到消息,问题仅在于后台。关于我应该如何解决问题以使 GCM 同时适用于 ios 和 android 的任何建议?

更新: 这是我在网上找到的:

关于实际通信,只要应用程序在 iOS 设备的后台,GCM 使用 APNS 发送消息,应用程序的行为类似于使用 Apple 的通知系统。但是当应用处于活动状态时,GCM 会直接与应用通信

所以我在前台模式下收到的消息:

[消息:新消息,collapse_key:do_not_collapse,来自:**************]

是来自 GCM 的直接消息(APNS 根本没有参与这件事)。所以问题是:APNS 是否重新格式化 GCM 发送给它的内容以遵守 ios 通知格式?如果是这样,我怎么知道 APNS 确实做了某事以及它是否以不同格式向我发送通知?有什么方法可以查看来自 APNS 的传入数据日志?

更新: 好的,我设法更改了消息的结构,现在在前台模式下我收到以下消息:

收到通知:["aps": {"alert":"Simple message","content-available":1},collapse_key:do_not_collapse,来自:************** ]

现在好像格式化好了,但是应用在后台时还是没有反应。 didReceiveRemoteNotifification completionHandler 没有被调用!我应该寻找什么,问题可能出在哪里?方括号会成为推送通知的问题吗?更准确地说,ios 不会从收到的通知中发布任何警报/徽章/横幅。

【问题讨论】:

标签: ios push-notification apple-push-notifications google-cloud-messaging


【解决方案1】:

献给每一个想了解 GCM 背景之谜的可怜人。我解决了它,问题出在格式上。我发布了正确的格式以及向 GCM 发送带有一些消息的 Http 请求所需的 Java 代码。 所以Http请求的头部应该有两个字段,分别是:

Authorization:key="here goes your GCM api key"
Content-Type:application/json for JSON data type

那么消息正文应该是一个带有“to”和“notification”键的json字典。例如:

{
  "to": "gcm_token_of_the_device",
  "notification": {
    "sound": "default",
    "badge": "2",
    "title": "default",
    "body": "Test Push!"
  }
}

这是使用 GCM 向指定设备发送推送的简单 java 程序(仅使用 java 库):

public class SendMessage {

    //config
    static String apiKey = ""; // Put here your API key
    static String GCM_Token = ""; // put the GCM Token you want to send to here
    static String notification = "{\"sound\":\"default\",\"badge\":\"2\",\"title\":\"default\",\"body\":\"Test Push!\"}"; // put the message you want to send here
    static String messageToSend = "{\"to\":\"" + GCM_Token + "\",\"notification\":" + notification + "}"; // Construct the message.

    public static void main(String[] args) throws IOException {
        try {

            // URL
            URL url = new URL("https://android.googleapis.com/gcm/send");

            System.out.println(messageToSend);
            // Open connection
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            // Specify POST method
            conn.setRequestMethod("POST");

            //Set the headers
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Authorization", "key=" + apiKey);
            conn.setDoOutput(true);

            //Get connection output stream
            DataOutputStream wr = new DataOutputStream(conn.getOutputStream());

            byte[] data = messageToSend.getBytes("UTF-8");
            wr.write(data);

            //Send the request and close
            wr.flush();
            wr.close();

            //Get the response
            int responseCode = conn.getResponseCode();
            System.out.println("\nSending 'POST' request to URL : " + url);
            System.out.println("Response Code : " + responseCode);

            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();

            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            in.close();

            //Print result
            System.out.println(response.toString()); //this is a good place to check for errors using the codes in http://androidcommunitydocs.com/reference/com/google/android/gcm/server/Constants.html

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

【讨论】:

  • 是的,用于发布的 Java 代码有效,我可以在通知抽屉中看到我的推送,但没有调用我的 didReceiveRemoteNotification* 方法。这意味着我正在接收推送,但是我无法拦截它?!你是怎么解决这个问题的?
  • 你应该把它放在http请求体中。在这个特定示例中,只需将 \"content_available\":\"1\" 作为 key 添加到 messageToSend 字符串。
  • 好的,谢谢!当我看到这个 SO 问题时,我意识到了这一点:stackoverflow.com/questions/30616302/…
  • 谢谢。 Google 文档中没有任何迹象表明您需要使用 "notification" 键才能使其工作。我们尝试使用"data",但在设备上什么也得不到,尽管 GCM 会告诉我们通知已成功发送。
  • 数据负载和通知负载都适用于iOS和Android。在 iOS 上,不同之处在于通知负载通过 APNS 发送,而数据负载通过 GCM 自己的连接发送,该连接仅在应用程序处于前台时才存在。所以,如果我想在 android 和 ios 中使用 GCM,payload 应该只包含通知?还是数据和通知都可以?
【解决方案2】:

尝试根据此处的文档在您的有效负载中设置优先级键:https://developers.google.com/cloud-messaging/concept-options#setting-the-priority-of-a-message

  • 在 APNs 术语中,正常优先级等于 5
  • 在 APNs 术语中高优先级等于 10

在这里,您可以在此处了解有关 Apple APN 优先级及其行为的更多信息: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/APNsProviderAPI.html

负载示例:

{
  "to": "gcm_device_token",
  "priority": "high",
  "content_available": false,
  "notification": {
    "sound": "default",
    "badge": "1",
    "title": "Push Title",
    "body": "Push Body"
  }
}

【讨论】:

  • 数据负载和通知负载都适用于iOS和Android。在 iOS 上,不同之处在于通知负载通过 APNS 发送,而数据负载通过 GCM 自己的连接发送,该连接仅在应用程序处于前台时才存在。所以,如果我想在 android 和 ios 中使用 GCM,payload 应该只包含通知?还是数据和通知都可以?
  • 最后一句中的数据是什么意思?
  • 有效载荷可以是“数据”或“通知”对吧?developers.google.com/cloud-messaging/concept-options
  • 我没有尝试这两种方法,但是从您附加的文档中看来,有效负载中允许通知和数据。
  • 什么是gcm_device_token??我在哪里可以买到??
【解决方案3】:

请务必注意,在 iOS 设备上,如果您使用 GCM 的应用已被终止(在应用切换器中滑动),那么只有在您发送带有“通知”的通知时,您的设备才会在收到消息时唤醒,“ content_available”和“priority”(设置为“high”)。如果你有一个或另一个,它可能会在应用程序被杀死时工作。但是一旦应用被终止,您必须在通知负载中包含所有这 3 个键。

类似这样的:

{
    "to": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "notification": {
        "title": "test",
        "body": "my message"
    },
    "priority": "high",
    "content_available": true
}

【讨论】:

    【解决方案4】:
    1. 这是为 C# 做的,认为这可能会有所帮助。我也有这个问题 将 content_available 添加到 true 后,它起作用了。根据 Apple文档,这就是操作系统理解存在的方式 应用在后台时的通知。

          JObject notification =new Object(
          new JProperty("to","put token which you get from running client application "),   
          new JProperty("content_available",true),
          new JProperty("priority","high"),
          new JProperty("notification",new JObject(
          new JProperty("title","message"),
          new JProperty("body","test message")
           ))
          );
      

    【讨论】:

      【解决方案5】:

      使用 nodeJS 和 node-gcm npm 库,我发现以下有效负载适用于 iOS,对于 Android,我发送的有效负载略有不同,因为我想在系统中显示它们之前拦截所有推送通知托盘:

      { dryRun: false,
        data: 
         { customKey1: 'CustomValue1',
           customKey2: 'CustomValue2',
           content_available: '1',
           priority: 'high' },
        notification: 
         { title: 'My Title',
           icon: 'ic_launcher',
           body: 'My Body',
           sound: 'default',
           badge: '2' } }
      

      当然,您需要确保您的 iOS 应用可以处理入站通知,但这应该在您的应用处于后台时进行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-26
        相关资源
        最近更新 更多