让 GCM 在后台为 iOS 设备工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31109514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 06:38:28  来源:igfitidea点击:

Making GCM work for iOS device in the background

iospush-notificationapple-push-notificationsgoogle-cloud-messaging

提问by Olexiy Burov

I'm trying to use GCM for IOS and Android clients. It seems to work fine with IOS when app is in the foreground, however, when the app is in the background, the notification center doesn't receive the message and didReceiveRemoteNotification with completionHandlerdoesn't get called.

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

I identified a problem as a wrongly formatted message from GCM to APNS. Namely, that's how it looks:

我发现问题是从 GCM 到 APNS 的消息格式错误。也就是说,这就是它的外观:

[message: New message, collapse_key: do_not_collapse, from: **************]
而 IOS 推送通知应该apsaps在通知中包含密钥,对吗?以及 content-available 设置为 1。例如:

{ "aps" : { "content-available" : 1 }, "data-id" : 345 }

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

By the way, in the foreground app receives the message anyway, the problem is only with the background. Any advice on how should I approach a problem, to make GCM work for both ios and android?

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

UPDATE: That is what I found on the net:

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

Regarding actual communication, as long as the application is in the background on an iOS device, GCM uses APNS to send messages, the application behaving similarly as using Apple's notification system. But when the app is active, GCM communicates directly with the app

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

So the message I received in the foreground mode:

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

[message: New message, collapse_key: do_not_collapse, from: **************]

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

Was the direct message from GCM(APNS did not participate in this affair at all). So the question is: does APNS reformat what GCM sends to it to adhere to ios notifications format? If so how do I know that APNS actually does something and whether it sends me a notification in different format ? Is there any way to view logs of incoming data from APNS ?

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

UPDATE:Okay, I managed to change the structure of the message and now in the foreground mode I receive the following message:

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

Notification received: ["aps": {"alert":"Simple message","content-available":1}, collapse_key: do_not_collapse, from: **************]

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

Now it seems to be well formatted, but there is still no reaction when the app is in the background. didReceiveRemoteNotifification completionHandler doesn't get called! What should I look for and where can a problem be ? Can the square bracket be a problem for push notification ? To be even more precise, ios doesn't post any alerts/badges/banners from that incoming notification.

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

采纳答案by Olexiy Burov

For every poor soul wondering in quest for an answer to GCM background mystery. I solved it and the problem was in the format. I'm posting the right format as well as Java code needed to send Http request to GCM with some message. So the Http request should have two field in the header, namely:

对于每个想寻求 GCM 背景之谜答案的可怜灵魂。我解决了,问题出在格式上。我发布了正确的格式以及将 Http 请求发送到 GCM 和一些消息所需的 Java 代码。所以Http请求的头部应该有两个字段,即:

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

then the message body should be a json dictionary with keys "to" and "notification". For example:

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

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

Here is the simple java program (using only java libraries) that sends push to a specified device, using GCM:

这是使用 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();
        }
    }
}

回答by jwenz723

It is important to note that on iOS devices, if your app using GCM has been killed (swiped in the app switcher) then your device will only awake upon receiving a message if you send a notification with the "notification", "content_available" and "priority" (set to "high"). If you have one or the other, it may work when the app has been killed. But once the app has been killed, you MUST have all 3 of these keys in your notification payload.

需要注意的是,在 iOS 设备上,如果您使用 GCM 的应用程序已被终止(在应用程序切换器中滑动),那么只有在您发送带有“notification”、“content_available”和“优先级”(设置为“高”)。如果你有一个或另一个,当应用程序被杀死时它可能会工作。但是一旦应用程序被杀死,您的通知负载中必须包含所有 3 个键。

Something like this:

像这样的东西:

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

回答by Marcin Kapusta

Try setting priority key in Your payload according to the docs here: https://developers.google.com/cloud-messaging/concept-options#setting-the-priority-of-a-message

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

  • normal priority is equal to 5 in APNs terminology
  • high priority is equal to 10 in APNs terminology
  • 正常优先级在 APNs 术语中等于 5
  • 高优先级在 APNs 术语中等于 10

Here You have more info about Apple APNs priorities and its behaviour here: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/APNsProviderAPI.html

在这里您有更多关于 Apple APNs 优先级及其行为的信息:https: //developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/APNsProviderAPI.html

Example payload:

示例有效载荷:

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

回答by ireshika piyumalie

  1. Did this for C#,think this could be help.I also had this problem after adding content_available to true , it worked. According to Apple documentation, that's the way OS understand that there is a notification when app is in background.

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

回答by GreensterRox

Using nodeJS and the node-gcmnpm library I've found that the following payload works for me for iOS, for Android I'm sending a slightly different payload because I want to intercept all push notifications before showing them in the system tray:

使用 nodeJS 和node-gcmnpm 库,我发现以下有效负载适用于 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' } }

Of course you'll need to ensure that your iOS app can handle the inbound notification but this should come through when your app is in the background.

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