Отправить сетевое сообщение, когда приложение iPhone закрыто - PullRequest
2 голосов
/ 08 января 2010

Приложение для iPhone поддерживает собственный сетевой протокол с использованием библиотеки CocoaAsyncSocket. Мне нужно иметь возможность отправлять сетевое сообщение, когда мое приложение для iPhone закрыто. Код, который отправляет сообщение, вызывается из делегата приложения, но приложение закрывается до того, как сообщение действительно исчезнет. Есть ли способ сохранить приложение живым достаточно долго, чтобы сообщение вышло?

Bruce

Ответы [ 3 ]

2 голосов
/ 08 января 2010

Я предполагаю, что вы уже звоните из приложения AppDelegate:

- (void)applicationWillTerminate:(UIApplication *)application

Но как вы обнаружили, нет никакой гарантии, что он будет вызван или будет допущен к завершению. Есть несколько вариантов, которые могут работать или не работать в зависимости от того, что вы пытаетесь сделать:

  • Если вам требуется, чтобы сервер выполнял какую-то операцию очистки, вызванную отсутствием клиентского приложения, вы можете попытаться наблюдать за закрытием сокета TCP на сервере и рассматривать его как событие запуска. Но если вам явно необходимо отправить данные обратно с закрытием, это может не сработать.

  • Если данные, которые вы отправляете назад, не чувствительны ко времени, вы можете сделать, как большинство библиотек аналитики, и кэшировать данные (вместе с uuid) на клиенте, а затем попытаться отправить их в приложение закрытие. Если он проходит, вы можете очистить кеш (или сделать это при следующем запуске приложения). Если этого не произойдет, он будет сохранен, и вы сможете отправить его при следующем запуске приложения. На сервере вы должны использовать uuid, чтобы избежать дублирования запросов.

  • Если материал чувствителен ко времени, то лучше всего использовать биение и отправлять периодически обновляемые значения на сервер. Затем, когда клиентское приложение умирает, сервер прерывает сердцебиение и может использовать последнее полученное значение в качестве конечной точки закрытия данных.

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

2 голосов
/ 08 января 2010

В документах от Apple это конкретно не указано, но смысл, который я получаю от просмотра Интернета и личного опыта, заключается в том, что у вас есть примерно 4–5 секунд после того, как пользователь нажимает кнопку «Домой», чтобы закрыть ваше приложение до того, как вы приложение фактически прекращает работу. IPhone OS контролирует это, поэтому вы не можете заблокировать завершение, чтобы позволить вашей программе завершиться первым. В основном, когда ваше время истекло, ваша программа убита.

Может быть и другое решение. Сначала я бы подтвердил, что вашему коду действительно требуется больше 5 секунд для запуска. Возможно, вы можете запустить его в ответ на нажатие кнопки и узнать, сколько времени он работает. Если это больше 5 секунд, вы, вероятно, столкнулись с проблемой тайм-аута.

Затем вы можете найти способ инициировать отправку сообщения с сервера, который всегда работает. У вас должно быть достаточно времени для запуска удаленного действия, которое, в свою очередь, может занять столько времени, сколько потребуется для его выполнения.

Или, возможно, вы можете сохранить жизненно важную информацию в файловой системе iPhone при выходе и отправить это сообщение при следующем запуске приложения, что теоретически должно дать вам достаточно времени.

Надеюсь, это поможет!

0 голосов
/ 08 января 2010

Как уже отмечали другие, невозможно быть абсолютно уверенным, что вы сможете отправить это, но есть способы помочь.

Как отмечает Кен, на практике вы получаете несколько секунд между "willTerminate" и принудительным завершением, поэтому обычно есть время сделать то, что вам нужно.

Проблема, с которой вы почти наверняка столкнетесь, связана с CocoaAsyncSocket. Когда вы получаете сообщение «willTerminate», вы находитесь в последнем цикле выполнения основного потока. Поэтому, если вы заблокируете основной поток, а CocoaAsyncSocket работает в основном потоке, он никогда не будет обработан. Насколько я помню, CocoaAsyncSocket не будет отправлять все данные до следующего цикла событий.

Поэтому один из подходов заключается в том, чтобы продолжать прокачивать цикл событий самостоятельно:

- (void)applicationWillTerminate:(UIApplication *)application
{
     // ...Send your message with CocoaAsyncSocket...

     while (! ...test to see if it sent...)
     {
         [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
     }
}

Я также рассмотрел вопрос о том, чтобы поместить эту работу в фоновый поток и позволить завершить основной поток, теоретически позволяя нам вернуться к Springboard, продолжая работу в течение нескольких секунд. Мне не сразу понятно, будет ли это работать правильно с помощью NSThread (которые отключены). Использование потоков POSIX (которые по умолчанию являются присоединяемыми) может работать, но, вероятно, позволяет обойти любые преимущества фонового потока. Во всяком случае, это что-то посмотреть, если полезно. В моих приложениях мы использовали подход «пост в следующий раз, когда мы запускаем», поскольку он всегда работает (даже в случае сбоя).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...