Production certificate error in push notification

2019-04-14 23:58发布

问题:

My app was getting push notification when I used Enterprise account with following push notification certificate in production environment:

Apple Production iOS Push Services

Then in order to publish my app in App store, I started using app store account, no matter what I try, apple creates production certificate in following name:

Apple Push Services

Then from this SO, I came to know that Apple has changed its naming in certificate. My issue is, I am using Push Sharp in server side and getting below error:

You have selected the Production server, yet your Certificate does not appear to be the Production certificate! Please check to ensure you have the correct certificate!

Both the solution given in that not working.

I updated Push Sharp from 2.2 to 3.0 beta, got many compile errors, even PushSharp class itself doesn't exist, then tried another solution from that thread.

Downloaded PushSharp from this and recompiled it by removing production line, still getting same error. Also that solution was not clear that much, I am not sure whether to comment certificate check line or what, I tried all but no luck

How to fix this?

回答1:

You can start using the new PushSharp 3.0.1 stable version it's really simple and awesome.

First you should goto and remove all the pushsharp 2 related dlls:

  • PushSharp.Core
  • PushSharp.Apple
  • PushSharp.Android

and etc also make sure to remove:

  • Newtonsoft.Json.dll (it will make a conflict and i will explain it)

Then goto your project and open nuget manager then search for latest stable version of PushSharp 3 nd download it.

Now you should use a new Pushsharp 3 APIs it's little different but more simpler so:

First create a class that contains all the brokers you want:

    public class AppPushBrokers
{
    public ApnsServiceBroker Apns { get; set; }
    public GcmServiceBroker Gcm { get; set; }
    public WnsServiceBroker wsb { get; set; }

}

Then on you business logic / Controller / ViewModel etc. you will need to write your PushNotification Business:

     public class NewPushHandler
    {
        #region  Constants
        public const string ANDROID_SENDER_AUTH_TOKEN = "xxxx";
        public const string WINDOWS_PACKAGE_NAME = "yyyy";
        public const string WINDOWS_PACKAGE_SECURITY_IDENTIFIER = "zzzz";
        public const string WINDOWS_CLIENT_SECRET = "hhhh";
        public const string APPLE_APP_NAME = "yourappname";
        public const string APPLE_PUSH_CERT_PASS = "applecertpass";
        #endregion

        #region Private members

        bool useProductionCertificate;
        string appleCertificateType;
        String appleCertName;
        String appleCertPath;
        byte[] appCertData;

        // logger
        ILogger logger;

        // Config (1- Define Config for each platform)
        ApnsConfiguration apnsConfig;
        GcmConfiguration gcmConfig;
        WnsConfiguration wnsConfig;

        #endregion

        #region Constructor
        public NewPushHandler()
        {
            // Initialize
            useProductionCertificate = true; // you can set it dynamically from config
            appleCertificateType = useProductionCertificate == true ? "production.p12" : "development.p12";
            appleCertName = APPLE_APP_NAME + "-" + appleCertificateType;
            appleCertPath = Path.Combine(Application.StartupPath, "Crt", appleCertName); // for web you should use HttpContext.Current.Server.MapPath(
            appCertData = File.ReadAllBytes(appleCertPath);
            var appleServerEnv = ApnsConfiguration.ApnsServerEnvironment.Production;
            logger = LoggerHandler.CreateInstance();

            // 2- Initialize Config
            apnsConfig = new ApnsConfiguration(appleServerEnv, appCertData, APPLE_PUSH_CERT_PASS);
            gcmConfig = new GcmConfiguration(ANDROID_SENDER_AUTH_TOKEN);
            wnsConfig = new WnsConfiguration(WINDOWS_PACKAGE_NAME, WINDOWS_PACKAGE_SECURITY_IDENTIFIER, WINDOWS_CLIENT_SECRET);

        }
        #endregion

        #region Private Methods

        #endregion 

        #region Public Methods

        public void SendNotificationToAll(string msg)
        {
// 3- Create a broker dictionary
            var apps = new Dictionary<string, AppPushBrokers> { {"com.app.yourapp",
         new AppPushBrokers {
            Apns = new ApnsServiceBroker (apnsConfig),
            Gcm = new GcmServiceBroker (gcmConfig),
            wsb = new WnsServiceBroker(wnsConfig)
        }}};



            #region Wire Up Events
// 4- events to fires onNotification sent or failure for each platform
            #region Android

            apps["com.app.yourapp"].Gcm.OnNotificationFailed += (notification, aggregateEx) =>
           {

               aggregateEx.Handle(ex =>
               {

                   // See what kind of exception it was to further diagnose
                   if (ex is GcmConnectionException)
                   {
                       // Something failed while connecting (maybe bad cert?)
                       Console.WriteLine("Notification Failed (Bad APNS Connection)!");
                   }
                   else
                   {
                       Console.WriteLine("Notification Failed (Unknown Reason)!");
                   }

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

            apps["com.app.yourapp"].Gcm.OnNotificationSucceeded += (notification) =>
            {
                //log success here or do what ever you want
            };
            #endregion

            #region Apple
            apps["com.app.yourapp"].Apns.OnNotificationFailed += (notification, aggregateEx) =>
            {

                aggregateEx.Handle(ex =>
                {

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

                        // Deal with the failed notification
                        var n = apnsEx.Notification;
                        logger.Error("Notification Failed: ID={n.Identifier}, Code={apnsEx.ErrorStatusCode}");

                    }
                    else if (ex is ApnsConnectionException)
                    {
                        // Something failed while connecting (maybe bad cert?)
                        logger.Error("Notification Failed (Bad APNS Connection)!");

                    }
                    else
                    {
                        logger.Error("Notification Failed (Unknown Reason)!");

                    }

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

            apps["com.app.yourapp"].Apns.OnNotificationSucceeded += (notification) =>
            {
                Console.WriteLine("Notification Sent!");
            };

            #endregion

            #endregion

            #region Prepare Notification

// 5- prepare the json msg for android and ios and any platform you want
            string notificationMsg = msg;
            string jsonMessage = @"{""message"":""" + notificationMsg +
                                        @""",""msgcnt"":1,""sound"":""custom.mp3""}";

            string appleJsonFormat = "{\"aps\": {\"alert\":" + '"' + notificationMsg + '"' + ",\"sound\": \"default\"}}";


            #endregion

            #region Start Send Notifications
// 6- start sending
            apps["com.app.yourapp"].Apns.Start();
            apps["com.app.yourapp"].Gcm.Start();
            //apps["com.app.yourapp"].wsb.Start();
            #endregion

            #region Queue a notification to send
// 7- Queue messages

            apps["com.app.yourapp"].Gcm.QueueNotification(new GcmNotification
            {
// You can get this from database in real life scenarios 
                RegistrationIds = new List<string> {
                    "ppppp", 
                  "nnnnn"
                },
                Data = JObject.Parse(jsonMessage),
                Notification = JObject.Parse(jsonMessage)



            });
            apps["com.app.yourapp"].Apns.QueueNotification(new ApnsNotification
            {
                DeviceToken = "iiiiiii",
                Payload = JObject.Parse(appleJsonFormat)

            });

            #endregion

            #region Stop Sending Notifications
            //8- Stop the broker, wait for it to finish   
            // This isn't done after every message, but after you're
            // done with the broker
            apps["com.app.yourapp"].Apns.Stop();
            apps["com.app.yourapp"].Gcm.Stop();
            //apps["com.app.yourapp"].wsb.Stop();

            #endregion

        }
        #endregion
    }

Important notes:

Some times specially when you works with IIS you can find an exceptions related to IOS certificate and the most common one:

“The credentials supplied to the package were not recognized”

This was due to many reasons for example your app pool user privilege or the certificate installed on the user account instead of local machine so try to disable the impersonation authentication from iis also check that it's really helpful Apple PushNotification and IIS



回答2:

My dirty quick fix was to download the source code for PushSharp v2.2 and then in the file ApplePushChannelSettings.cs I commented out the check about production and test certificates:

        void CheckProductionCertificateMatching(bool production)
    {
        if (this.Certificate != null)
        {
            var issuerName = this.Certificate.IssuerName.Name;
            var subjectName = this.Certificate.SubjectName.Name;

            if (!issuerName.Contains("Apple"))
                throw new ArgumentException("Your Certificate does not appear to be issued by Apple!  Please check to ensure you have the correct certificate!");

            /*
            if (production && !subjectName.Contains("Apple Production IOS Push Services"))
                throw new ArgumentException("You have selected the Production server, yet your Certificate does not appear to be the Production certificate!  Please check to ensure you have the correct certificate!");


            if (!production && !subjectName.Contains("Apple Development IOS Push Services") && !subjectName.Contains("Pass Type ID"))
                    throw new ArgumentException("You have selected the Development/Sandbox (Not production) server, yet your Certificate does not appear to be the Development/Sandbox certificate!  Please check to ensure you have the correct certificate!");                
             */
        }
        else
            throw new ArgumentNullException("You must provide a Certificate to connect to APNS with!");
    }

And replaced the PushSharp.Apple.dll file in my project.

Hopefully my customer will upgrade to dotnet 4.5 so we can use PushSharp 4 and do it the correct way.