c# - 无法发送带有分发证书的 APNS 消息

标签 c# objective-c apple-push-notifications x509certificate2 sslstream

我已经使用开发证书和 gateway.sandbox.push.apple.com 设置并成功测试了 APNS 消息传递。
当我切换到我的分发证书和 gateway.push.apple.com 时,消息没有通过,我得到一个异常:

无法将数据写入传输连接:已建立的连接已被主机中的软件中止。

我已经按照这些教程生成了 p12 证书:

http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1 http://code.google.com/p/apns-sharp/wiki/HowToCreatePKCS12Certificate

我发送通知的服务器软件是一个使用 SslStreamX509Certificate2 类的 .NET 应用程序。

连接代码如下:

    /// <summary>
    /// Establish connection to Apple's Push Notification System using the variables in the config file.
    /// </summary>
    public void ConnectToAPNS()
    {
        try
        {
            int port = Convert.ToInt32(Config.SSL_PORT ); // 2195
                // pick the target address
            String hostname = Config.SSL_PATH;  // gateway.push.apple.com

            //load certificate
            string certificatePath = Config.CERT_FILE; //.p12 certification file
            string certificatePassword = Config.CERT_PASS;
            byte[] p12Data = System.IO.File.ReadAllBytes(certificatePath);

            X509Certificate2 clientCertificate = new X509Certificate2(p12Data, certificatePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);

            X509Certificate2Collection certificatesCollection = new X509Certificate2Collection();
            certificatesCollection.Add(clientCertificate);

            RemoteCertificateValidationCallback remote = new RemoteCertificateValidationCallback(ValidateServerCertificate);

            client = new TcpClient(hostname, port);
            sslStream = new SslStream(
                    client.GetStream(),
                    false,
                    remote,
                    null
            );

            try
            {
                sslStream.AuthenticateAsClient(hostname, certificatesCollection, SslProtocols.Tls, true);

            }
            catch (AuthenticationException e)
            {
                IQLogger.Logger.LogError("Push NotifyMessenger ConnectToAPNS: " + e.Message);
                client.Close();
                sslStream = null;
                client = null;
                return;
            }
        }catch (Exception e)
        {
            IQLogger.Logger.LogError("PushNotifyMessenger ConnectToAPNS: " + e.Message);
            sslStream = null;
            client = null;
            return;
        }
        return;
    }

    /// <summary>
    /// Call back checks for validation error
    /// </summary>
    /// <returns></returns>
    public static bool ValidateServerCertificate( object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        try{
            if (sslPolicyErrors == SslPolicyErrors.None)
                return true;
        }
        catch 
        {
        }
        IQLogger.Logger.LogError("PushNotifyMessenger ValidateServerCertificate: sslPolicyErrors" + sslPolicyErrors);
        // Do not allow this client to communicate with unauthenticated servers. 
        return false;
    }

这是发送消息的代码:

    /// <summary>
    /// I send a text message to a specified device ID. I provide an example of how to format a message for the APNS system. 
    /// The message must be formatted in Json and be sent as a byte array.
    /// </summary>
    /// <param name="deviceId"> A string containing 64 characters representing hexidecimal values of a 32 byte device code</param>
    /// <param name="msgPrompt">The text that will popup on the device </param>
    /// <param name="msgData"> XML that will be put in the XML json Section. This data will be invisible to the recipient's user, 
    /// but will be accessible by the recipient program</param>
    public void SendMessage(string deviceId, string msgPrompt, string msgData)
    {
        try{
            if (client == null || sslStream == null)
            {
                ConnectToAPNS();
            }

            // Encode a test message into a byte array.
            MemoryStream memoryStream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(memoryStream);

            writer.Write((byte)0);  //The command
            writer.Write((byte)0);  //The first byte of the deviceId length (big-endian first byte)
            writer.Write((byte)32); //The deviceId length (big-endian second byte)

            byte[] arDeviceID = ConvertDeviceID(deviceId);//System.Text.Encoding.UTF8.GetBytes(deviceId);
            writer.Write(arDeviceID);

            String payload = "{\"aps\":{\"alert\":\"" + msgPrompt + "\",\"badge\":1,\"xml\":\"" + msgData + "\"}}";

            writer.Write((byte)0); //First byte of payload length; (big-endian first byte)
            writer.Write((byte)payload.Length); //payload length (big-endian second byte)

            byte[] b1 = System.Text.Encoding.UTF8.GetBytes(payload);
            writer.Write(b1);
            writer.Flush();

            byte[] array = memoryStream.ToArray();
            sslStream.Write(array);   // <<<<<<<<<< exception thrown here
            sslStream.Flush();

        }
        catch (Exception e)
        {
            IQLogger.Logger.LogError("PushNotifyMessenger.SendMessage: " + e.Message);
            return;
        }

    }

在第二次或第三次尝试发送 APNS 消息时抛出异常。但是,没有一条消息可以传递到设备。我可以换回我的开发证书并且此代码运行良好(并且 APNS 消息到达设备)。

在寻找解决问题的过程中,我遇到了一些帖子,指出开发证书以某种方式干扰了部署,但我不明白这是怎么发生的,也不知道我应该怎么做才能解决它。

在此先感谢您提供的任何帮助。

最佳答案

确保您使用的是 APNS 实时服务器 URL ssl://gateway.push.apple.com:2195

关于c# - 无法发送带有分发证书的 APNS 消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17554118/

相关文章:

c# - 将 SYSTEMTIME( native C++)转换为日期时间 (C#)

c# - 更新语句以跟踪数据库中的 SortOrder

c# - c# 中两个整数中的至少一个可随机整除

ios - 如何设置和获取指针 Swift 的值

ios - 未收到 Apple 推送通知/可能存在配置文件问题?

c# - 如何在可接受的误差范围内检查两位小数的相等性

ios - 当收到低内存警告时,在处理过程中停止 PerformRequestsWithTarget

ios - 如何将 .c 文件包含到我的 ios 应用程序中?

ios - 多个具有相同证书的APNS提供商

iphone - 苹果推送通知 - 没有有效的 'aps-environment' 已经尝试了我在网上看到的所有解决方案?