如何在 C# .Net 上通过 GCM 发送 Android 推送通知

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16248468/
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-10 00:32:48  来源:igfitidea点击:

How to send Android push notifications via GCM on C# .Net

c#androidgoogle-cloud-messaging

提问by Pavan Welihinda

I'm new to all Android GCM push notifications and I have read stack posts but couldn't get a straight answer.I have also read Create push notification in androidto get a better understanding of how GCM works. I have also used the gcm-demo-server and gcm-demo-client provided by the SDK. However, here are my doubts and what I have tried so far:

我是所有 Android GCM 推送通知的新手,我已经阅读了堆栈帖子,但无法得到直接的答案。我还阅读了在 android 中创建推送通知以更好地了解 GCM 的工作原理。我还使用了 SDK 提供的 gcm-demo-server 和 gcm-demo-client。但是,这是我的疑虑以及我迄今为止的尝试:

  1. Regarding the link I have put, the phone which has the app registers to get the registration key. Is this a unique key for all phones which uses the same app?
  2. Does this registration key expires in any case? (E.g. App running on background)
  3. Assuming that I have the registration key, I have tried the following code snippet to push notification via GCM to my app. This is written on c# .net. Please let me know whether what I have mentioned above can be achieved using the following code snippet:

         private string SendGCMNotification(string apiKey, string postData, string postDataContentType = "application/json")
        {
            ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);
    
            // MESSAGE CONTENT
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
    
            // CREATE REQUEST
            HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send");
            Request.Method = "POST";
            Request.KeepAlive = false;
            Request.ContentType = postDataContentType;
            Request.Headers.Add(string.Format("Authorization: key={0}", apiKey));
            Request.ContentLength = byteArray.Length;
    
            Stream dataStream = Request.GetRequestStream();
            dataStream.Write(byteArray, 0, byteArray.Length);
            dataStream.Close();
    
            // SEND MESSAGE
            try
            {
                WebResponse Response = Request.GetResponse();
                HttpStatusCode ResponseCode = ((HttpWebResponse)Response).StatusCode;
                if (ResponseCode.Equals(HttpStatusCode.Unauthorized) || ResponseCode.Equals(HttpStatusCode.Forbidden))
                {
                    var text = "Unauthorized - need new token";
                }
                else if (!ResponseCode.Equals(HttpStatusCode.OK))
                {
                    var text = "Response from web service isn't OK";
                }
    
                StreamReader Reader = new StreamReader(Response.GetResponseStream());
                string responseLine = Reader.ReadToEnd();
                Reader.Close();
    
                return responseLine;
            }
            catch (Exception e)
            {
            }
            return "error";
        }
    
  4. Is there a direct way of sending push notifications without the phone first being registered in our custom server?

  1. 关于我放置的链接,具有该应用程序的手机会注册以获取注册密钥。这是所有使用相同应用程序的手机的唯一密钥吗?
  2. 这个注册码在任何情况下都会过期吗?(例如在后台运行的应用程序)
  3. 假设我有注册码,我尝试了以下代码片段通过 GCM 将通知推送到我的应用程序。这是在 c# .net 上写的。请让我知道是否可以使用以下代码片段来实现我上面提到的内容:

         private string SendGCMNotification(string apiKey, string postData, string postDataContentType = "application/json")
        {
            ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);
    
            // MESSAGE CONTENT
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
    
            // CREATE REQUEST
            HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send");
            Request.Method = "POST";
            Request.KeepAlive = false;
            Request.ContentType = postDataContentType;
            Request.Headers.Add(string.Format("Authorization: key={0}", apiKey));
            Request.ContentLength = byteArray.Length;
    
            Stream dataStream = Request.GetRequestStream();
            dataStream.Write(byteArray, 0, byteArray.Length);
            dataStream.Close();
    
            // SEND MESSAGE
            try
            {
                WebResponse Response = Request.GetResponse();
                HttpStatusCode ResponseCode = ((HttpWebResponse)Response).StatusCode;
                if (ResponseCode.Equals(HttpStatusCode.Unauthorized) || ResponseCode.Equals(HttpStatusCode.Forbidden))
                {
                    var text = "Unauthorized - need new token";
                }
                else if (!ResponseCode.Equals(HttpStatusCode.OK))
                {
                    var text = "Response from web service isn't OK";
                }
    
                StreamReader Reader = new StreamReader(Response.GetResponseStream());
                string responseLine = Reader.ReadToEnd();
                Reader.Close();
    
                return responseLine;
            }
            catch (Exception e)
            {
            }
            return "error";
        }
    
  4. 是否有直接发送推送通知的方法,而无需先在我们的自定义服务器中注册手机?

回答by Freelancer

Refer Code:

参考代码:

public class AndroidGCMPushNotification
{
    public AndroidGCMPushNotification()
    {
        //
        // TODO: Add constructor logic here
        //
    }
    public string SendNotification(string deviceId, string message)
    {
        string SERVER_API_KEY = "server api key";        
        var SENDER_ID = "application number";
        var value = message;
        WebRequest tRequest;
        tRequest = WebRequest.Create("https://android.googleapis.com/gcm/send");
        tRequest.Method = "post";
        tRequest.ContentType = " application/x-www-form-urlencoded;charset=UTF-8";
        tRequest.Headers.Add(string.Format("Authorization: key={0}", SERVER_API_KEY));

        tRequest.Headers.Add(string.Format("Sender: id={0}", SENDER_ID));

        string postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message=" + value + "&data.time=" + System.DateTime.Now.ToString() + "&registration_id=" + deviceId + "";
        Console.WriteLine(postData);
        Byte[] byteArray = Encoding.UTF8.GetBytes(postData);
        tRequest.ContentLength = byteArray.Length;

        Stream dataStream = tRequest.GetRequestStream();
        dataStream.Write(byteArray, 0, byteArray.Length);
        dataStream.Close();

        WebResponse tResponse = tRequest.GetResponse();

        dataStream = tResponse.GetResponseStream();

        StreamReader tReader = new StreamReader(dataStream);

        String sResponseFromServer = tReader.ReadToEnd();


        tReader.Close();
        dataStream.Close();
        tResponse.Close();
        return sResponseFromServer;
    }
}

Referance Link:

参考链接:

http://www.codeproject.com/Tips/434338/Android-GCM-Push-Notification

http://www.codeproject.com/Tips/434338/Android-GCM-Push-Notification

回答by Nikhil Gaur

Just for the information for new visitors on this post, if you want to send same message to multiple devices then simply send comma separated device ids in registration_id parameter of request.

仅针对此帖子中新访问者的信息,如果您想向多个设备发送相同的消息,则只需在请求的 registration_id 参数中发送逗号分隔的设备 ID。

Here is a nice article on this http://www.codewithasp.net/2015/11/send-message-gcm-c-sharp-single-multiple.html

这是一篇关于这个http://www.codewithasp.net/2015/11/send-message-gcm-c-sharp-single-multiple.html的好文章

回答by Mina Gabriel

Thisnever worked for me and it is hard to debug plus passing a list of registration token is not clear -would expect passing a string array instead of comma separated string - , the fact that this is very simple post request i created my own class with a method that return the server response, and it works very well:

对我来说从来没有用过并且很难调试并且传递注册令牌列表不清楚 - 希望传递一个字符串数组而不是逗号分隔的字符串 - 事实上,这是非常简单的发布请求,我创建了自己的类一种返回服务器响应的方法,并且效果很好:

Usage

用法

       //Registration Token 
        string[] registrationIds ={"diks4vp5......","erPjEb9....."};

        AndroidGcmPushNotification gcmPushNotification = new 
        AndroidGcmPushNotification(
            "API KEY", registrationIds, "Hello World"
            );
        gcmPushNotification.SendGcmNotification();

Class

班级

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Web.Script.Serialization;


public class AndroidGcmPushNotification
{
private readonly string _apiAccessKey;
private readonly string[] _registrationIds;
private readonly string _message;
private readonly string _title;
private readonly string _subtitle;
private readonly string _tickerText;
private readonly bool _vibrate;
private readonly bool _sound;

public AndroidGcmPushNotification(string apiAccessKey, string[] registrationIds, string message, string title = "",
    string subtitle = "", string tickerText = "", bool vibrate = true, bool sound = true )
{
    _apiAccessKey = apiAccessKey;
    _registrationIds = registrationIds;
    _message = message;
    _title = title;
    _subtitle = subtitle;
    _tickerText = tickerText;
    _vibrate = vibrate;
    _sound = sound;
}

public string SendGcmNotification()
{

    //MESSAGE DATA
    GcmPostData data = new GcmPostData()
    {
        message = _message,
        title = _title,
        subtitle = _subtitle,
        tickerText = _tickerText,
        vibrate = _vibrate,
        sound = _sound
    };

    //MESSAGE FIELDS 
    GcmPostFields fields = new GcmPostFields();
    fields.registration_ids = _registrationIds;
    fields.data = data;

    //SERIALIZE TO JSON 
    JavaScriptSerializer jsonEncode = new JavaScriptSerializer();

    //CONTENTS
    byte[] byteArray = Encoding.UTF8.GetBytes(jsonEncode.Serialize(fields));

    //REQUEST
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send");
    request.Method = "POST";
    request.KeepAlive = false;
    request.ContentType = "application/json";
    request.Headers.Add($"Authorization: key={_apiAccessKey}");
    request.ContentLength = byteArray.Length;

    Stream dataStream = request.GetRequestStream();
    dataStream.Write(byteArray, 0, byteArray.Length);
    dataStream.Close();


    //SEND REQUEST
    try
    {
        WebResponse response = request.GetResponse();
        {
            StreamReader reader = new StreamReader(response.GetResponseStream());
            string responseLine = reader.ReadToEnd();
            reader.Close();

            return responseLine;
        }
    }
    catch (Exception e)
    {
        return e.Message;
    }

}
private class GcmPostFields
{
    public string[] registration_ids { get; set; }
    public GcmPostData data { get; set; }

}
private class GcmPostData
{
    public string message { get; set; }
    public string title { get; set; }
    public string subtitle { get; set; }
    public string tickerText { get; set; }
    public bool vibrate { get; set; }
    public bool sound { get; set; }
}

}

回答by dariol

There is package PushSharp. Allows to communicate with almost every popular notification api.

有包PushSharp。允许与几乎所有流行的通知 api 进行通信。

Example code:

示例代码:

// Configuration
var config = new GcmConfiguration ("GCM-SENDER-ID", "AUTH-TOKEN", null);

// Create a new broker
var gcmBroker = new GcmServiceBroker (config);

// Wire up events
gcmBroker.OnNotificationFailed += (notification, aggregateEx) => {

    aggregateEx.Handle (ex => {

        // See what kind of exception it was to further diagnose
        if (ex is GcmNotificationException) {
            var notificationException = (GcmNotificationException)ex;

            // Deal with the failed notification
            var gcmNotification = notificationException.Notification;
            var description = notificationException.Description;

            Console.WriteLine ($"GCM Notification Failed: ID={gcmNotification.MessageId}, Desc={description}");
        } else if (ex is GcmMulticastResultException) {
            var multicastException = (GcmMulticastResultException)ex;

            foreach (var succeededNotification in multicastException.Succeeded) {
                Console.WriteLine ($"GCM Notification Failed: ID={succeededNotification.MessageId}");
            }

            foreach (var failedKvp in multicastException.Failed) {
                var n = failedKvp.Key;
                var e = failedKvp.Value;

                Console.WriteLine ($"GCM Notification Failed: ID={n.MessageId}, Desc={e.Description}");
            }

        } else if (ex is DeviceSubscriptionExpiredException) {
            var expiredException = (DeviceSubscriptionExpiredException)ex;

            var oldId = expiredException.OldSubscriptionId;
            var newId = expiredException.NewSubscriptionId;

            Console.WriteLine ($"Device RegistrationId Expired: {oldId}");

            if (!string.IsNullOrWhitespace (newId)) {
                // If this value isn't null, our subscription changed and we should update our database
                Console.WriteLine ($"Device RegistrationId Changed To: {newId}");
            }
        } else if (ex is RetryAfterException) {
            var retryException = (RetryAfterException)ex;
            // If you get rate limited, you should stop sending messages until after the RetryAfterUtc date
            Console.WriteLine ($"GCM Rate Limited, don't send more until after {retryException.RetryAfterUtc}");
        } else {
            Console.WriteLine ("GCM Notification Failed for some unknown reason");
        }

        // Mark it as handled
        return true;
    });
};

gcmBroker.OnNotificationSucceeded += (notification) => {
    Console.WriteLine ("GCM Notification Sent!");
};

// Start the broker
gcmBroker.Start ();

foreach (var regId in MY_REGISTRATION_IDS) {
    // Queue a notification to send
    gcmBroker.QueueNotification (new GcmNotification {
        RegistrationIds = new List<string> { 
            regId
        },
        Data = JObject.Parse ("{ \"somekey\" : \"somevalue\" }")
    });
}

// Stop the broker, wait for it to finish   
// This isn't done after every message, but after you're
// done with the broker
gcmBroker.Stop ();

回答by Charitha Goonewardena

Code looks bit long but it works. I just sent a push notification to my phone after struggling 2 days by implementing the following code in C# project. I referred a link regarding this implementation, But couldn't find it to post here. So will share my code with you. If you want to test the Notification online you may visit to this link.

代码看起来有点长,但它有效。通过在 C# 项目中实现以下代码,我在挣扎了 2 天后刚刚向我的手机发送了推送通知。我参考了有关此实现的链接,但找不到在此处发布的链接。所以将与您分享我的代码。如果您想在线测试通知,您可以访问此链接

note : I have hardcorded apiKey, deviceId and postData, please pass the apiKey,deviceId and postData in your request and remove them from the method body. If you want pass message string also

注意:我已经硬编码了 apiKey、deviceId 和 postData,请在您的请求中传递 apiKey、deviceId 和 postData,并将它们从方法主体中删除。如果您还想传递消息字符串

public string SendGCMNotification(string apiKey, string deviceId, string postData)
{
    string postDataContentType = "application/json";
    apiKey = "AIzaSyC13...PhtPvBj1Blihv_J4"; // hardcorded
    deviceId = "da5azdfZ0hc:APA91bGM...t8uH"; // hardcorded

    string message = "Your text";
    string tickerText = "example test GCM";
    string contentTitle = "content title GCM";
    postData =
    "{ \"registration_ids\": [ \"" + deviceId + "\" ], " +
      "\"data\": {\"tickerText\":\"" + tickerText + "\", " +
                 "\"contentTitle\":\"" + contentTitle + "\", " +
                 "\"message\": \"" + message + "\"}}";


    ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);

    //
    //  MESSAGE CONTENT
    byte[] byteArray = Encoding.UTF8.GetBytes(postData);

    //
    //  CREATE REQUEST
    HttpWebRequest Request = (HttpWebRequest)WebRequest.Create("https://android.googleapis.com/gcm/send");
    Request.Method = "POST";
    Request.KeepAlive = false;
    Request.ContentType = postDataContentType;
    Request.Headers.Add(string.Format("Authorization: key={0}", apiKey));
    Request.ContentLength = byteArray.Length;

    Stream dataStream = Request.GetRequestStream();
    dataStream.Write(byteArray, 0, byteArray.Length);
    dataStream.Close();

    //
    //  SEND MESSAGE
    try
    {
        WebResponse Response = Request.GetResponse();
        HttpStatusCode ResponseCode = ((HttpWebResponse)Response).StatusCode;
        if (ResponseCode.Equals(HttpStatusCode.Unauthorized) || ResponseCode.Equals(HttpStatusCode.Forbidden))
        {
            var text = "Unauthorized - need new token";
        }
        else if (!ResponseCode.Equals(HttpStatusCode.OK))
        {
            var text = "Response from web service isn't OK";
        }

        StreamReader Reader = new StreamReader(Response.GetResponseStream());
        string responseLine = Reader.ReadToEnd();
        Reader.Close();

        return responseLine;
    }
    catch (Exception e)
    {
    }
    return "error";
}

public static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
    return true;
}

You may not familiar with words like apiKey, deviceId. Dont worry i will explain what are they and how to create those.

apiKey、deviceId之类的词你可能不太熟悉。别担心,我会解释它们是什么以及如何创建它们。

apiKey
What & why :This a key that will be used when sending requests to GCM server.
How to create : Refer this post

deviceId
What & why : This id also known as RegistrationId. This is a unique id to identify the device. When you want to send a notification to a specific device you need this id.
How to create: This depends on how you implement the application. For cordova i used a simple pushNotification PluginYou can simply create a deviceId/RegistrationId using this plugin. To do that you need to have a senderId. Google how to create a senderId it is really simple =)

apiKey
What & 为什么:这是向 GCM 服务器发送请求时将使用的密钥。
如何创建:参考这篇文章

deviceId
What & 为什么:这个 id 也称为 RegistrationId。这是用于标识设备的唯一 ID。当您想向特定设备发送通知时,您需要此 ID。
如何创建:这取决于您如何实现应用程序。对于cordova,我使用了一个简单的pushNotification Plugin您可以使用这个插件简单地创建一个deviceId/RegistrationId。为此,您需要有一个senderId。Google 如何创建 senderId 真的很简单 =)

If anyone needs some help leave a comment.

Happy Coding.
-Charitha-

如果有人需要帮助,请发表评论。

快乐编码。
-Charitha-

回答by Charitha Goonewardena

I have worked with Android Applications and IOS application using Firebase's FCM. This code is working .Middle layer is ASP.NET API.You start a project in visual studio and select API.To be create a controller.Your server_api_key and sender id adding Web.config file.

我使用 Firebase 的 FCM 处理过 Android 应用程序和 IOS 应用程序。此代码正在工作。中间层是 ASP.NET API。您在 Visual Studio 中启动一个项目并选择 API。要创建一个控制器。您的 server_api_key 和发件人 ID 添加 Web.config 文件。

Adding user fcm server_api_key and sender id.

添加用户 fcm server_api_key 和发件人 ID。

<appSettings>
    <add key="SERVER_API_KEY" value=""/>
    <add key="SENDER_ID" value=""/>
</appSettings>

The below code to add your controller

以下代码添加您的控制器

 using System;
    using System.Net;
    using System.Web.Http;
    using System.Web.Script.Serialization;
    using System.Configuration;
    using System.IO;

    namespace pushios.Controllers
        {

        public class HomeController : ApiController
            {
                [HttpGet]

        [Route("sendmessage")]

                public IHttpActionResult SendMessage()
              {
                    var data = new {
                        to = "Device Token",
                        data = new
                        {
                           //To be adding your json data
                            body="Test",
                            confId= "",
                            pageTitle= "test",
                            pageFormat= "",
                            dataValue= "",
                            title= "C#",
                            webviewURL= "",
                            priority = "high",
                            notificationBlastID = "0",
                            status = true
                        }
                    };
                    SendNotification(data);
                    return Ok();
                }
                public void SendNotification(object data)
                {
                    var Serializer = new JavaScriptSerializer();
                    var json = Serializer.Serialize(data);
                    Byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(json);

                    SendNotification(byteArray);
                }
                public void SendNotification(Byte[] byteArray)
                {

                    try
                    {
                        String server_api_key = ConfigurationManager.AppSettings["SERVER_API_KEY"];
                        String senderid = ConfigurationManager.AppSettings["SENDER_ID"];

                        WebRequest type = WebRequest.Create("https://fcm.googleapis.com/fcm/send");
                        type.Method = "post";
                        type.ContentType = "application/json";
                        type.Headers.Add($"Authorization: key={server_api_key}");
                        type.Headers.Add($"Sender: id={senderid}");

                        type.ContentLength = byteArray.Length;
                        Stream datastream = type.GetRequestStream();
                        datastream.Write(byteArray, 0, byteArray.Length);
                        datastream.Close();

                        WebResponse respones = type.GetResponse();
                        datastream = respones.GetResponseStream();
                        StreamReader reader = new StreamReader(datastream);

                        String sresponessrever = reader.ReadToEnd();
                        reader.Close();
                        datastream.Close();
                        respones.Close();

                    }
                    catch (Exception)
                    {
                        throw;
                    }

                }
            }
        }