iPhone Push Notification issue with c#

2019-06-02 05:21发布

问题:

I cannot send the notification to iphone. Everything seems fine, as the service works out fine, but to message to iphone.

Here is the code:

using (NetworkStream networkStream = client.GetStream())
            {
                Console.WriteLine("Client connected.");

                //X509Certificate clientCertificate = new X509Certificate(@"C:\Users\yagizozturk\Documents\Visual Studio 2010\Projects\GarantiKampanya\Garanti.Web.Service\apns-prod.pem", "");
                X509Certificate clientCertificate = new X509Certificate(@"C:\Users\yagizozturk\Documents\Visual Studio 2010\Projects\GarantiKampanya\Garanti.Web.Service\apns-prod-cert.p12", "1234567");
                X509CertificateCollection clientCertificateCollection = new X509CertificateCollection(new X509Certificate[1] { clientCertificate });

                // Create an SSL stream that will close the client's stream.
                SslStream sslStream = new SslStream(
                    client.GetStream(),
                    false,
                    new RemoteCertificateValidationCallback(ValidateServerCertificate),
                    null
                    );

                try
                {
                    sslStream.AuthenticateAsClient("gateway.sandbox.push.apple.com", clientCertificateCollection, SslProtocols.Default, false);
                }
                catch (AuthenticationException e)
                {
                    Console.WriteLine("Exception: {0}", e.Message);
                    if (e.InnerException != null)
                    {
                        Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                    }
                    Console.WriteLine("Authentication failed - closing the connection.");
                    client.Close();
                    return;
                }
            }
        }

        string token = "f5aaa8a729613480c79270085e881c435535dac4704dc00b082bfa8fc84aca10";
        //string token = "f5aaa8a7 29613480 c7927008 5e881c43 5535dac4 704dc00b 082bfa8f c84aca90";
        System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();


        byte[] myByteArray = new byte[10000000];

        myByteArray = encoding.GetBytes(token);

        //int i = 0;
        //foreach(char c in token.ToCharArray())
        //{
        //  myByteArray [i] = (byte)c;
        //  i++;
        //}

        GeneratePayload(myByteArray, "test", "default");
    }

    private static byte[] GeneratePayload(byte[] deviceToken, string message, string sound)
    {
        MemoryStream memoryStream = new MemoryStream();

        // Command
        memoryStream.WriteByte(0);

        byte[] tokenLength = BitConverter.GetBytes((Int16)32);
        Array.Reverse(tokenLength);
        // device token length
        memoryStream.Write(tokenLength, 0, 2);

        // Token
        memoryStream.Write(deviceToken, 0, 32);

        // String length
        string apnMessage = string.Format("{{\"aps\":{{\"alert\":{{\"body\":\"{0}\",\"action-loc-key\":null}},\"sound\":\"{1}\"}}}}",
            message,
            sound);

        byte[] apnMessageLength = BitConverter.GetBytes((Int16)apnMessage.Length);
        Array.Reverse(apnMessageLength);
        // message length
        memoryStream.Write(apnMessageLength, 0, 2);

        // Write the message
        memoryStream.Write(System.Text.ASCIIEncoding.ASCII.GetBytes(apnMessage), 0, apnMessage.Length);

        return memoryStream.ToArray();
    }


    // The following method is invoked by the RemoteCertificateValidationDelegate.
    public static bool ValidateServerCertificate(
          object sender,
          X509Certificate certificate,
          X509Chain chain,
          SslPolicyErrors sslPolicyErrors)
    {
        if (sslPolicyErrors == SslPolicyErrors.None)
            return true;

        Console.WriteLine("Certificate error: {0}", sslPolicyErrors);

        // Do not allow this client to communicate with unauthenticated servers.
        return false;
    }

回答1:

I got the answer. Here is a complete code to send push notifications from c#.

    public bool ConnectToAPNS()
    {
        X509Certificate2Collection certs = new X509Certificate2Collection();

        // Add the Apple cert to our collection
        certs.Add(getServerCert());

        // Apple development server address
        string apsHost;

        if (getServerCert().ToString().Contains("Production"))
            apsHost = "gateway.push.apple.com";
        else
            apsHost = "gateway.sandbox.push.apple.com";

        // Create a TCP socket connection to the Apple server on port 2195
        TcpClient tcpClient = new TcpClient(apsHost, 2195);

        // Create a new SSL stream over the connection
        sslStream = new SslStream(tcpClient.GetStream());

        // Authenticate using the Apple cert
        sslStream.AuthenticateAsClient(apsHost, certs, SslProtocols.Default, false);

        //PushMessage();

        return true;
    }

    private X509Certificate getServerCert()
    {
        X509Certificate test = new X509Certificate();

        //Open the cert store on local machine
        X509Store store = new X509Store(StoreLocation.CurrentUser);

        if (store != null)
        {
            // store exists, so open it and search through the certs for the Apple Cert
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certs = store.Certificates;

            if (certs.Count > 0)
            {
                int i;
                for (i = 0; i < certs.Count; i++)
                {
                    X509Certificate2 cert = certs[i];

                    if (cert.FriendlyName.Contains("Apple Production Push Services: KFDLV3XL6Y:ZJPGDMQBKC"))
                    {
                        //Cert found, so return it.
                        return certs[i];
                    }
                }
            }
            return test;
        }
        return test;
    }

    private static byte[] HexToData(string hexString)
    {
        if (hexString == null)
            return null;

        if (hexString.Length % 2 == 1)
            hexString = '0' + hexString; // Up to you whether to pad the first or last byte

        byte[] data = new byte[hexString.Length / 2];

        for (int i = 0; i < data.Length; i++)
            data[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);

        return data;
    }

    public bool PushMessage(string token, string message)
    {
        String cToken = token;
        String cAlert = message;
        int iBadge = 1;

        // Ready to create the push notification
        byte[] buf = new byte[256];
        MemoryStream ms = new MemoryStream();
        BinaryWriter bw = new BinaryWriter(ms);
        bw.Write(new byte[] { 0, 0, 32 });

        byte[] deviceToken = HexToData(cToken);
        bw.Write(deviceToken);

        bw.Write((byte)0);

        // Create the APNS payload - new.caf is an audio file saved in the application bundle on the device
        string msg = "{\"aps\":{\"alert\":\"" + cAlert + "\",\"badge\":" + iBadge.ToString() + ",\"sound\":\"new.caf\"}}";

        // Write the data out to the stream
        bw.Write((byte)msg.Length);
        bw.Write(msg.ToCharArray());
        bw.Flush();

        if (sslStream != null)
        {
            sslStream.Write(ms.ToArray());
            return true;
        }

        return false;
    }