iOS - Невозможно вызвать API, когда приложение работает в фоновом режиме - PullRequest
1 голос
/ 09 января 2020

Я занимаюсь разработкой приложения, которое позволяет пользователям участвовать в опросах. Приложение может работать в режиме офлайн / онлайн.

Вот концепция:

  1. В случае онлайн: когда пользователь входит в опрос и нажимает кнопку отправки, Приложение будет вызывать API (используя httpClient) для отправки информации об опросе на сервер.
  2. В случае автономного режима: когда пользователь входит в опрос и нажимает кнопку отправки, приложение сохранит информацию об опросе на местном уровне. После того, как мобильное устройство подключится к сети, оно будет вызывать API для отправки информации об опросе с локального на сервер.

Рабочий процесс:

  • Для android, это работает для следующих случаев:

    Когда онлайн: - Создать опрос, опрос будет отправлен на сервер.

    Когда оффлайн:

    1. Создать опрос => опрос сохранен на местном уровне; 1.1. Оставить приложение все еще открытым, а затем подключиться к сети => опрос отправлен на сервер; 1.2. Нажмите кнопку «Домой», чтобы приложение запустило фон => Подключить сеть => опрос отправлен на сервер; 1.3. Пользователи принудительно выходят из приложения => Подключить сеть (в этом случае опрос не будет отправлен на сервер) => Открыть приложение (опрос будет синхронизирован с сервером)
  • Для iOS, это работает для следующих случаев:

    Когда он-лайн: Создать опрос, опрос будет синхронизироваться c с сервером (нужно подождать около 5 секунд, прежде чем закрывать приложение. , это будет ошибка при вызове API).

    В автономном режиме:

    1. Создать опрос => опрос сохраняется в локальном режиме. 1.1. Оставить приложение все еще открытым, а затем подключиться к сети => опрос отправлен на сервер; 1.2. Нажмите кнопку «Домой», чтобы запустить приложение в фоновом режиме => Подключить сеть (в этом случае опрос не будет отправлен на сервер) => Открыть приложение (опрос будет отправлен на сервер); 1.3. Пользователи принудительно выходят из приложения => Подключить сеть (в этом случае опрос не будет отправлен на сервер) => Открыть приложение (опрос будет отправлен на сервер)

Итак, я вижу что все отлично работает на Android. Однако возникла проблема, если приложение запускало фон в iOS. Опрос отправляется на сервер, только если пользователи открывают приложение. Для iOS я использую Silent Notification. Получит pu sh Уведомление приложения каждые 5 минут для вызова API вызова (отправка опроса на сервер), когда приложение работает в фоновом режиме. На данный момент приложение может вызывать API, когда приложение получает уведомление, но при вызове API произошла ошибка.

  • Я использовал iPhone и проверил на Facebook Messenger, если отправляю сообщение в автономном режиме, а затем нажмите кнопку «Домой», чтобы запустить фон (не приложение принудительного выхода). После подключения к сети сообщение будет отправлено без необходимости открывать приложение.

Вот ошибка:

NSLocalizedDescription = Сеть соединение было потеряно., NSErrorFailingURLStringKey = [URL], NSErrorFailingURLKey = [URL], _kCFStreamErrorDomainKey = 4} --- Конец внутренней трассировки стека исключений --- в System. Net .Http.NSUrlSessionHandler.SendAsyn c (система . Net .Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x104e298d0 + 0x0091f> в: 0 в системе. Net t, System.Nullable 1 [T] токен) <0x105c15460 + 0x00984> в: 0 в SurveyApp.Service.SyncSer Vice.Push (System.Collections.Generi c .IList 1 [T] синхронизации) <0x105c1d7a0 + 0x001e7> в: 0 в SurveyApp.Service.SyncService.PushSurveys () <0x105c1d1b0 + 0x0028b »в системе: . Net .Http.HttpRequestException Сетевое соединение потеряно. в системе. Net .Http.NSUrlSessionHandler.SendAsync (система. Net .Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) <0x104e298d0 + 0x0091f> в: 0 в системе. * 1092. , Токен System.Nullable 1 [T]) <0x105c15460 + 0x00984> в: 0 в SurveyApp.Service.SyncService.Push (синхронизация System.Collections.Generi c .IList 1 [T]) <0x105c1d7a0 + 0x001e7> в: 0 at SurveyApp.Service.SyncService.PushSurveys () <0x105c1d1b0 + 0x0028b> в: 0 Foundation.NSErrorException Error Domain = NSURLErrorDomain Code = -1005 "" Сетевое соединение потеряно. "" Использовать

Вот код, который я обрабатываю для вызова API (используйте httpClient):

public async Task<T> PostAsync<T, TP>(string url, TP t, CancellationToken? token = null)
{
    try
    {
        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
        ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

        var content = JsonConvert.SerializeObject(t);
        HttpContent httpContent = new StringContent(content);
        httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

        using (var httpClient = new HttpClient { Timeout = TimeSpan.FromMinutes(5), DefaultRequestHeaders = { ConnectionClose = true } })
        {
            HttpResponseMessage responseMessage;

            if (token != null)
            {
                responseMessage = await httpClient.PostAsync(url, httpContent, token.Value);
            }
            else
            {
                var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5));
                responseMessage = await httpClient.PostAsync(url, httpContent, cancellationTokenSource.Token);
            }

            if (responseMessage.IsSuccessStatusCode == false)
            {
                throw new Exception("Request has problem");
            }

            var responseContent = await responseMessage.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<T>(responseContent, DefaultSerializerSettings);
        }
    }
    catch (TaskCanceledException)
    {
        await Task.Delay(5000);
        return await PostAsync<T, TP>(url, t, token);
    }
    catch (Exception e)
    {
        _logger.Error(e);
        throw;
    }
}

public async Task<T> PostSurveyPhotoWithDataAsync<T>(string url, string file, SurveyPhoto surveyPhoto)
{
    try
    {
        ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
        ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

        using (var formData = new MultipartFormDataContent())
        {
            using (var httpClient = new HttpClient { Timeout = TimeSpan.FromMinutes(10), DefaultRequestHeaders = { ConnectionClose = true } })
            {
                using (var streamReader = new StreamReader(file))
                {
                    formData.Add(new StreamContent(streamReader.BaseStream), "File", file);
                    formData.Add(new StringContent(surveyPhoto.KeyId), "KeyId");
                    formData.Add(new StringContent(surveyPhoto.FileName), "FileName");
                    formData.Add(new StringContent(surveyPhoto.SurveySyncId), "SurveyId");

                    var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(5));
                    var responseMessage = await httpClient.PostAsync(url, formData, cancellationTokenSource.Token);

                    streamReader.Close();

                    if (responseMessage.IsSuccessStatusCode == false)
                    {
                        throw new Exception("Request has problem");
                    }

                    var responseContent = await responseMessage.Content.ReadAsStringAsync();
                    return JsonConvert.DeserializeObject<T>(responseContent, DefaultSerializerSettings);
                }
            }
        }
    }
    catch (TaskCanceledException)
    {
        await Task.Delay(5000);
        return await PostSurveyPhotoWithDataAsync<T>(url, file, surveyPhoto);
    }
    catch (Exception e)
    {
        _logger.Error(e);
        throw;
    }
}

Есть какое-нибудь решение, документ или пример кода, которые могут помочь мне решить эту проблему?

1 Ответ

0 голосов
/ 09 января 2020

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

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

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