c# - Apple 在 C# 中推送通知提供程序

标签 c# ios objective-c push-notification

我对 Apple 推送通知服务完全陌生。我正在尝试为我的应用程序实现它。我在 google 和 stackoverflow 中搜索得很好,但并不满意。我正在尝试在 C# 中实现提供程序。我也尝试过 MoonAPNs。

这里的任何人都可以向我推荐非常简单的分步教程。我已经获得了 ios 开发者和 apn 证书以及 p12 key 。那我需要帮助。 提前致谢。

最佳答案

这是我正在使用的基础架构和流程:

简要概述: 我用 PushSharp用于与 APNS 服务器通信。我有一个 SQL Server 后端数据库设置来处理所有发送的订阅和通知。我还有一个虚拟服务器(实际上是几个),所有服务器都复制了 .p12 证书。这些服务器具有检查表中是否有任何需要发出的推送通知的进程,然后将数据集传递给 PushSharp 进程。

详细规范: 表 1 - APNS_订阅

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]

表 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]

我通过这个 SP 添加订阅(这是通过每个实现 APNS 的 iPhone 应用程序通过网络服务调用的:

[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

通过此 SP 添加推送通知:

[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   

这是从几个不同数据库中的几个不同地方调用的: 执行 [ins_APNS_PushNote] @网络ID ,@iOSApplicationName ,@AlertMessage ,@声音文件 ,@RequestedBy

为虚拟服务器 (PushSharp) 检索这些 APNS 请求的 SP:

[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 

现在介绍我对 PushSharp 应用所做的更改。真的只是归结为两种方法: 静态无效主要(字符串[]参数) { 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...");         
    }

我在 PushSharp 解决方案中添加了一个控制台项目,并将控制台部署到 APNS 服务器。此控制台应用程序根据每分钟运行的计划任务触发。

如果您有更多问题,请告诉我。去年我一直在企业环境中使用这个过程,没有遇到任何问题。完美运行。

关于c# - Apple 在 C# 中推送通知提供程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14277018/

相关文章:

c# - 无法将透明代理强制转换为来自 AppDomain 的类型

ios - 如何在MKMapView中一次显示多个MKPointAnnotation的标注?

iphone - 当 iPhone 进入横向模式时执行方法

iphone - 当 UITabBar 选项卡更改时关闭 DetailController?

objective-c - 自动生成代码以创建具有未知类的对象

c# - 如何在 C# 中正确处理相关但不同类的调用方法

c# - 组合与继承。我哪里做错了?

c# - 如何立即抛出 List<CustomExceptionObj> 异常

objective-c - EXC_BAD_ACCESS 切换到 ARC 时出错

ios - .xib 文件如何自动关联并加载到我的 ViewController?