Apple-Push-Benachrichtigungsanbieter in c#

Apple-Push-Benachrichtigungsanbieter in c#

Hier ist die Infrastruktur und der Prozess, den ich verwende:

Kurzer Überblick:Ich verwende PushSharp für die Kommunikation mit den APNS-Servern. Ich habe ein SQL Server-Backend-DB-Setup, um alle Abonnements und Benachrichtigungen zu verarbeiten, die gesendet werden. Ich habe auch einen virtuellen Server (eigentlich mehrere), auf den alle die .p12-Zertifikate kopiert wurden. Diese Server verfügen über einen Prozess, der die Tabelle auf Push-Benachrichtigungen überprüft, die versendet werden müssen, und das Dataset dann an den PushSharp-Prozess weitergibt.

Detaillierte Spezifikationen:Tabelle 1 – APNS_Subscriptions

CREATE TABLE [dbo].[APNS_Subscriptions](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [DeviceToken] [varchar](250) NULL,
    [DeviceID] [varchar](250) NULL,
    [NetworkID] [varchar](250) NULL,
    [Application] [varchar](250) NULL,
    [AddedOn] [datetime] NULL,
    [Active] [bit] NULL,
    [Dev] [bit] NULL,
    [BadgeCount] [int] NOT NULL,
 CONSTRAINT [PK_APNSSubscriptions] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Tabelle 2 – APNS_PushNotifications

CREATE TABLE [dbo].[APNS_PushNotifications](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [DeviceToken] [varchar](250) NULL,
    [AlertMessage] [varchar](250) NULL,
    [BadgeNumber] [int] NULL,
    [SoundFile] [varchar](250) NULL,
    [ApplicationName] [varchar](250) NULL,
    [AddedOn] [datetime] NULL,
    [AddedBy] [varchar](250) NULL,
    [ProcessedOn] [datetime] NULL,
    [ViewedOnDeviceDateTime] [datetime] NULL,
 CONSTRAINT [PK_APNS_PushNotifications] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Ich füge Abonnements über diesen SP hinzu (dieser wird über einen Webservice über jede iPhone-App aufgerufen, die APNS implementiert:

[ins_APNS_Sub]
    @MyDeviceID VARCHAR(250) ,
    @MyDeviceToken VARCHAR(250) ,
    @MyApplicationName VARCHAR(250)
AS 
    DECLARE @Count AS INT

    SET @Count = ( SELECT   COUNT(id)
                   FROM     dbo.APNS_Subscriptions
                   WHERE    DeviceID = @MyDeviceID
                            AND DeviceToken = @MyDeviceToken
                            AND [Application] = @MyApplicationName
                 )

    IF @Count = 0 
        BEGIN
            DECLARE @NetworkID AS VARCHAR(250)
            SET @NetworkID = ( SELECT TOP 1
                                        networkid
                               FROM     dbo.AuthenticatedDevices
                               WHERE    deviceid = @MyDeviceID
                                        AND COALESCE(banned, 0) = 0
                               ORDER BY lastupdatedon DESC
                             )

            IF @NetworkID IS NOT NULL 
                BEGIN

                    INSERT  INTO dbo.APNS_Subscriptions
                            ( DeviceToken ,
                              DeviceID ,
                              NetworkID ,
                              [Application] ,
                              AddedOn ,
                              Active
                            )
                    VALUES  ( @MyDeviceToken , -- DeviceToken - varchar(250)
                              @MyDeviceID , -- DeviceID - varchar(250)
                              @NetworkID , -- NetworkID - varchar(250)
                              @MyApplicationName , -- Application - varchar(250)
                              CURRENT_TIMESTAMP , -- AddedOn - datetime
                              1  -- Active - bit
                            )
                END
        END

Push-Benachrichtigungen werden über diesen SP hinzugefügt:

[ins_APNS_PushNote]
    @MyNetworkID VARCHAR(250) ,  -- NetworkID of recipient or ALL to go to all recipients
    @MyApplicationName VARCHAR(250) ,  -- Application Name for the iOS app
    @APNSAlertMessage VARCHAR(225) , -- Alert Message (Required)
    @APNSSoundFile VARCHAR(250) = NULL ,
    @WhoRequested VARCHAR(250) -- Process Name that called this SP
AS 


   -- Get the current badge count, make a temp table and increment the appropriate rows in the Sub table
    DECLARE @UpdateTable AS TABLE
        (
          DeviceToken VARCHAR(250) ,
          NetworkID VARCHAR(250) ,
          ApplicationName VARCHAR(250) ,
          BadgeCount INT
        )

    IF @MyNetworkID = 'ALL' 
        BEGIN

            INSERT  INTO @UpdateTable
                    ( DeviceToken ,
                      NetworkID ,
                      ApplicationName ,
                      BadgeCount
                    )
                    SELECT  DeviceToken ,
                            NetworkID ,
                            [Application] ,
                            BadgeCount
                    FROM    dbo.APNS_Subscriptions
                    WHERE   [Application] = @MyApplicationName
                            AND COALESCE(Dev, 0) = 0

            UPDATE  @UpdateTable
            SET     BadgeCount = BadgeCount + 1

            UPDATE  sub
            SET     sub.BadgeCount = temp.BadgeCount
            FROM    dbo.APNS_Subscriptions sub
                    INNER JOIN @UpdateTable temp ON temp.DeviceToken = sub.DeviceToken
                                                    AND temp.NetworkID = sub.NetworkID
                                                    AND temp.ApplicationName = sub.[Application]

            INSERT  INTO dbo.APNS_PushNotifications
                    ( DeviceToken ,
                      AlertMessage ,
                      BadgeNumber ,
                      SoundFile ,
                      ApplicationName ,
                      AddedOn ,
                      AddedBy

                    )
                    SELECT  sub.DeviceToken ,
                            @APNSAlertMessage ,
                            temp.BadgeCount ,
                            @APNSSoundFile ,
                            @MyApplicationName ,
                            CURRENT_TIMESTAMP ,
                            @WhoRequested
                    FROM    dbo.APNS_Subscriptions sub
                            INNER JOIN dbo.AuthenticatedDevices ad ON ad.deviceid = sub.DeviceID
                            INNER JOIN @UpdateTable temp ON temp.DeviceToken = sub.DeviceToken
                                                            AND temp.ApplicationName = sub.[Application]
                    WHERE   COALESCE(ad.banned, 0) = 0
                            AND sub.[Application] = @MyApplicationName
                              --  AND ad.networkid = @MyNetworkID
                            AND COALESCE(sub.Dev, 0) = 0
        END    
    ELSE 
        BEGIN

            DECLARE @Count AS INT = ( SELECT    COUNT(id)
                                      FROM      dbo.APNS_Subscriptions
                                      WHERE     NetworkID = @MyNetworkID
                                                AND Active = 1
                                                AND [Application] = @MyApplicationName
                                    )


            IF @Count = 0 
                BEGIN
                    RETURN
                END     

            INSERT  INTO @UpdateTable
                    ( DeviceToken ,
                      NetworkID ,
                      ApplicationName ,
                      BadgeCount
                    )
                    SELECT  DeviceToken ,
                            NetworkID ,
                            [Application] ,
                            BadgeCount
                    FROM    dbo.APNS_Subscriptions
                    WHERE   [Application] = @MyApplicationName
                            AND COALESCE(Dev, 0) = 0
                            AND NetworkID = @MyNetworkID

            UPDATE  @UpdateTable
            SET     BadgeCount = BadgeCount + 1

            UPDATE  sub
            SET     sub.BadgeCount = temp.BadgeCount
            FROM    dbo.APNS_Subscriptions sub
                    INNER JOIN @UpdateTable temp ON temp.DeviceToken = sub.DeviceToken
                                                    AND temp.NetworkID = sub.NetworkID
                                                    AND temp.ApplicationName = sub.[Application]

            INSERT  INTO dbo.APNS_PushNotifications
                    ( DeviceToken ,
                      AlertMessage ,
                      BadgeNumber ,
                      SoundFile ,
                      ApplicationName ,
                      AddedOn ,
                      AddedBy

                    )
                    SELECT  sub.DeviceToken ,
                            @APNSAlertMessage ,
                            temp.BadgeCount ,
                            @APNSSoundFile ,
                            @MyApplicationName ,
                            CURRENT_TIMESTAMP ,
                            @WhoRequested
                    FROM    dbo.APNS_Subscriptions sub
                            INNER JOIN dbo.AuthenticatedDevices ad ON ad.deviceid = sub.DeviceID
                            INNER JOIN @UpdateTable temp ON temp.DeviceToken = sub.DeviceToken
                                                            AND temp.ApplicationName = sub.[Application]
                    WHERE   COALESCE(ad.banned, 0) = 0
                            AND sub.[Application] = @MyApplicationName
                            AND sub.networkid = @MyNetworkID
                            AND COALESCE(sub.Dev, 0) = 0
                            AND COALESCE(sub.Active, 0) = 1

        END   

Dies wird von mehreren verschiedenen Stellen in mehreren verschiedenen DBs auf diese Weise aufgerufen:EXECUTE [ins_APNS_PushNote]@NetworkID,@iOSApplicationName,@AlertMessage,@SoundFile,@RequestedBy

Der SP, der diese APNS-Anforderungen für den virtuellen Server (PushSharp) abruft:

[get_APNSToSend]
AS 
    BEGIN

        DECLARE @CurrentTimestamp AS DATETIME = CURRENT_TIMESTAMP

        UPDATE dbo.APNS_PushNotifications
        SET ProcessedOn = CURRENT_TIMESTAMP
        WHERE ProcessedOn IS NULL

        SELECT  id ,
                DeviceToken ,
                AlertMessage ,
                BadgeNumber ,
                SoundFile ,
                ai.APNSDistCertFile AS APNSCertFile
        FROM    dbo.APNS_PushNotifications apns
                INNER JOIN dbo.ApplicationInfo ai ON ai.ApplicationName = apns.ApplicationName
        WHERE   ProcessedOn = @CurrentTimestamp
                AND ai.APNSDistCertFile IS NOT NULL


    END 

Nun zu den Änderungen, die ich an der PushSharp-App vorgenommen habe. Läuft wirklich nur auf zwei Methoden hinaus:static void Main(string[] args){checkForPushRequest();}

    static void checkForPushRequest()
    {
        string YourConnString = "YourConnectionStringToTheDBGoesHere";

            Stored_Procedure SP = new Stored_Procedure {
            Name = "get_APNSToSend",
            Parameters = new List<SqlParameter>()
        };

        try {
            System.Data.DataTable dt = DatabaseOperations.Execute_Database_Command(YourConnString, SP, true);

            if ((dt != null) && !(dt.Rows.Count < 1)) {
                foreach (System.Data.DataRow dRow in dt.Rows) {
                    string deviceToken = Convert.ToString(dRow[1]);
                    string alertMessage = Convert.ToString(dRow[2]);
                    int badgeNumber =  Convert.ToInt16(dRow[3]);
                    string soundFile = Convert.ToString(dRow[4]);
                    string apnsCertFileToUse = Convert.ToString(dRow[5]);
                    sendPush(deviceToken, alertMessage, soundFile, badgeNumber, apnsCertFileToUse);
                }
            }
        } catch (Exception ex) {
            // Handle your exception
        }
    }

    static void sendPush(string DeviceToken, string AlertMessage, string SoundFile, int BadgeNumber, string apnsCertFileToUse)
    {
        //Create our service    
        PushService push = new PushService();

        //Wire up the events
        push.Events.OnDeviceSubscriptionExpired += new PushSharp.Common.ChannelEvents.DeviceSubscriptionExpired(Events_OnDeviceSubscriptionExpired);
        //push.Events.OnDeviceSubscriptionIdChanged += new PushSharp.Common.ChannelEvents.DeviceSubscriptionIdChanged(Events_OnDeviceSubscriptionIdChanged);
        push.Events.OnChannelException += new PushSharp.Common.ChannelEvents.ChannelExceptionDelegate(Events_OnChannelException);
        push.Events.OnNotificationSendFailure += new PushSharp.Common.ChannelEvents.NotificationSendFailureDelegate(Events_OnNotificationSendFailure);
        push.Events.OnNotificationSent += new PushSharp.Common.ChannelEvents.NotificationSentDelegate(Events_OnNotificationSent);

        //Configure and start Apple APNS
        // IMPORTANT: Make sure you use the right Push certificate.  Apple allows you to generate one for connecting to Sandbox,
        //   and one for connecting to Production.  You must use the right one, to match the provisioning profile you build your
        //   app with!  
        //  This comes from the ApplicationInfo table.  Each app that supports APNS has it's own certfile name in the column
        string certFileToUse = "C:\\APNS_Certs\\" + apnsCertFileToUse;

        var appleCert = File.ReadAllBytes(certFileToUse);

        //IMPORTANT: If you are using a Development provisioning Profile, you must use the Sandbox push notification server 
        //  (so you would leave the first arg in the ctor of ApplePushChannelSettings as 'false')
        //  If you are using an AdHoc or AppStore provisioning profile, you must use the Production push notification server
        //  (so you would change the first arg in the ctor of ApplePushChannelSettings to 'true')
        push.StartApplePushService(new ApplePushChannelSettings(false, appleCert, "P12PasswordHere"));

        //Fluent construction of an iOS notification
        //IMPORTANT: For iOS you MUST MUST MUST use your own DeviceToken here that gets generated within your iOS app itself when the Application Delegate
        //  for registered for remote notifications is called, and the device token is passed back to you
        push.QueueNotification(NotificationFactory.Apple()
            .ForDeviceToken(DeviceToken)
            .WithAlert(AlertMessage)
            .WithSound(SoundFile)
            .WithBadge(BadgeNumber));

        //Console.WriteLine("Waiting for Queue to Finish...");

        //Stop and wait for the queues to drains
        push.StopAllServices(true);

       // Console.WriteLine("Queue Finished, press return to exit...");         
    }

Ich habe der PushSharp-Lösung ein Konsolenprojekt hinzugefügt und die Konsole auf dem APNS-Server bereitgestellt. Diese Konsolen-App wird basierend auf einer geplanten Aufgabe ausgelöst, die jede Minute ausgeführt wird.

Wenn Sie weitere Fragen haben, lassen Sie es mich wissen. Ich habe diesen Prozess im letzten Jahr in einer Unternehmensumgebung verwendet und hatte keine Probleme. Funktioniert einwandfrei.


Da Sie MoonAPNS verwenden, würde ich vorschlagen, die 4-teilige Anleitung zum Senden von Apple-Push-Benachrichtigungen in ASP.NET und C# vom Autor der Bibliotheken zu lesen.