Как отправить push-уведомление более чем на одно устройство (iOS)?

Я пытаюсь оптимизировать push-уведомления на своем сервере. Пока я отправляю их по одному (со старой библиотекой), и это занимает некоторое время (4 часа).

Я реорганизовал свой сервис, чтобы отправить уведомление с большим количеством токенов устройства (на данный момент я пробовал с партиями по 500 токенов). Для этого я использую библиотеку Redth/PushSharp. Я следовал примеру кода, а затем адаптировал его для отправки уведомления на несколько токенов устройств.

PushService service = new PushService();

//Wire up the events
service.Events.OnDeviceSubscriptionExpired += new PushSharp.Common.ChannelEvents.DeviceSubscriptionExpired(Events_OnDeviceSubscriptionExpired);
service.Events.OnDeviceSubscriptionIdChanged += new PushSharp.Common.ChannelEvents.DeviceSubscriptionIdChanged(Events_OnDeviceSubscriptionIdChanged);
service.Events.OnChannelException += new PushSharp.Common.ChannelEvents.ChannelExceptionDelegate(Events_OnChannelException);
service.Events.OnNotificationSendFailure += new PushSharp.Common.ChannelEvents.NotificationSendFailureDelegate(Events_OnNotificationSendFailure);
service.Events.OnNotificationSent += new PushSharp.Common.ChannelEvents.NotificationSentDelegate(Events_OnNotificationSent);
service.Events.OnChannelCreated += new PushSharp.Common.ChannelEvents.ChannelCreatedDelegate(Events_OnChannelCreated);
service.Events.OnChannelDestroyed += new PushSharp.Common.ChannelEvents.ChannelDestroyedDelegate(Events_OnChannelDestroyed);

//Configure and start ApplePushNotificationService
string p12Filename = ...
string p12FilePassword = ...

var appleCert = File.ReadAllBytes(p12Filename);

service.StartApplePushService(new ApplePushChannelSettings(true, appleCert, p12FilePassword));

var appleNotification = NotificationFactory.Apple();

foreach (var itemToProcess in itemsToProcess)
{
    itemToProcess.NotificationDateTime = DateTime.Now;
    mobile.SubmitChanges();

    string deviceToken = GetCleanDeviceToken(itemToProcess.MobileDevice.PushNotificationIdentifier);
    appleNotification.ForDeviceToken(deviceToken);
}

service.QueueNotification(appleNotification
    .WithAlert(itemsToProcess[0].MobileDeviceNotificationText.Text)
    .WithSound("default")
    .WithBadge(0)
    .WithCustomItem("View", itemsToProcess[0].Value.ToString()));

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

Затем я попытался отправить 3 уведомления на 2 устройства. Их получило только первое устройство (и проблема не связана с устройством, потому что я пробовал с обоими по отдельности). Сразу после этого в классе PushChannelBase создается исключение OperationCanceledException. . Так что я не знаю, что не так. Есть идеи?


person Alexis    schedule 07.12.2012    source источник
comment
Привет. Это позволяет отправлять одиночные push-сообщения на несколько устройств в одном запросе. Я провел НИОКР и внедрил код, готовый и протестированный на 5-10 устройствах.   -  person V.J.    schedule 22.02.2016


Ответы (2)


Вы должны поставить в очередь отдельное уведомление для каждого обрабатываемого элемента.
Невозможно установить несколько токенов устройств в одном уведомлении. Возникнет OperationCanceledException, потому что вы это делаете.

person Jacco    schedule 08.12.2012
comment
Привет. Это позволяет отправлять одиночные push-сообщения на несколько устройств в одном запросе. Я провел НИОКР и внедрил код, готовый и протестированный на 5-10 устройствах. - person V.J.; 22.02.2016

Пример: консольное приложение C#

Это предполагает

  1. у вас есть действующие сертификаты на производство и разработку
  2. вы сохранили несколько токенов устройств в своей базе данных
  3. у вас есть уведомление, которое приходит из вашей базы данных
  4. Вы используете библиотеку PushSharp.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using PushSharp;
    using PushSharp.Core;
    using PushSharp.Apple;
    using System.IO;
    
    namespace MyNotification
    {
        class Program
        {
            //args may take "true" or "false" to indicate the app is running for
            //development or production (Default = false which means Development)
            static void Main(string[] args)
            {
                bool isProduction = false;
                if (args != null && args.Length == 1)
                {
                    Console.Write(args[0] + Environment.NewLine);
                    bool.TryParse(args[0], out isProduction);
                }
                try
                {
                    //Gets a notification that needs sending from database
                    AppNotification notification = AppNotification.GetNotification();
                    if (notification != null && notification.ID > 0)
                    {          
                        //Gets all devices to send the above notification to         
                        List<IosDevice> devices = IosDevice.GetDevices(!isProduction);
                        if (devices != null && devices.Count > 0)
                        {
                            PushBroker push = new PushBroker();//a single instance per app
                            //Wire up the events for all the services that the broker registers
                            push.OnNotificationSent += NotificationSent;
                            push.OnChannelException += ChannelException;
                            push.OnServiceException += ServiceException;
                            push.OnNotificationFailed += NotificationFailed;
                            push.OnDeviceSubscriptionExpired += DeviceSubscriptionExpired;
                            push.OnChannelCreated += ChannelCreated;
                            push.OnChannelDestroyed += ChannelDestroyed;
                            //make sure your certifcates path are all good  
                            string apnsCertFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../Certificate/Certificates_Apple_Push_Production.p12");
                            if (!isProduction)
                                apnsCertFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../Certificate/Certificates_Apple_Push_Development.p12");
                            var appleCert = File.ReadAllBytes(apnsCertFile);
                            push.RegisterAppleService(new ApplePushChannelSettings(isProduction, appleCert, "135TrID35")); //Extension method
    
                            foreach (IosDevice device in devices)
                            {
                                //if it is required to send additional information as well as the alert message, uncomment objects[] and WithCustomItem 
                                //object[] obj = { "North", "5" };
    
                                push.QueueNotification(new AppleNotification()
                               .ForDeviceToken(device.DeviceToken)
                               .WithAlert(DateTime.Now.ToString())//(notification.AlertMessage)
                                    //.WithCustomItem("Link", obj)
                               .WithBadge(device.BadgeCount + 1)
                               .WithSound(notification.SoundFile));//sound.caf
                            }
                            push.StopAllServices(waitForQueuesToFinish: true);
                        }
                    }
                    Console.WriteLine("Queue Finished, press return to exit...");
                    Console.ReadLine();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    Console.ReadLine();
                }
            }
    
            static void NotificationSent(object sender, INotification notification)
            {
                Console.WriteLine("Sent: " + sender + " -> " + notification);
            }
    
            static void NotificationFailed(object sender, INotification notification, Exception notificationFailureException)
            {
                Console.WriteLine("Failure: " + sender + " -> " + notificationFailureException.Message + " -> " + notification);
            }
    
            static void ChannelException(object sender, IPushChannel channel, Exception exception)
            {
                Console.WriteLine("Channel Exception: " + sender + " -> " + exception);
            }
    
            static void ServiceException(object sender, Exception exception)
            {
                Console.WriteLine("Service Exception: " + sender + " -> " + exception);
            }
    
            static void DeviceSubscriptionExpired(object sender, string expiredDeviceSubscriptionId, DateTime timestamp, INotification notification)
            {
                Console.WriteLine("Device Subscription Expired: " + sender + " -> " + expiredDeviceSubscriptionId);
            }
    
            static void ChannelDestroyed(object sender)
            {
                Console.WriteLine("Channel Destroyed for: " + sender);
            }
    
            static void ChannelCreated(object sender, IPushChannel pushChannel)
            {
                Console.WriteLine("Channel Created for: " + sender);
            }  
        }
    
    }
    
person user890255    schedule 06.11.2013
comment
есть ли способ отправить push-уведомление на несколько устройств без цикла для каждого? например массовый толчок? все сразу.. - person ; 02.06.2014
comment
это выполняет массовое нажатие, цикл for each просто добавляет устройства в очередь push. я использую это на производстве и работает как шарм :) - person user890255; 05.06.2014
comment
Привет. Это позволяет отправлять одиночные push-сообщения на несколько устройств в одном запросе. Я провел НИОКР и внедрил код, готовый и протестированный на 5-10 устройствах. - person V.J.; 22.02.2016
comment
@В.Дж. можешь объяснить как ты это сделал? Поскольку на данный момент (июль 2021 г.) нет известного интерфейса для APNS. Объясните, как вы это сделали (без использования каких-то циклов). - person thomasgalliker; 17.07.2021