Я занимаюсь разработкой приложения, которое позволяет пользователям участвовать в опросах. Приложение может работать в режиме офлайн / онлайн.
Вот концепция:
- В случае онлайн: когда пользователь входит в опрос и нажимает кнопку отправки, Приложение будет вызывать API (используя
httpClient
) для отправки информации об опросе на сервер. - В случае автономного режима: когда пользователь входит в опрос и нажимает кнопку отправки, приложение сохранит информацию об опросе на местном уровне. После того, как мобильное устройство подключится к сети, оно будет вызывать API для отправки информации об опросе с локального на сервер.
Рабочий процесс:
Для android, это работает для следующих случаев:
Когда онлайн: - Создать опрос, опрос будет отправлен на сервер.
Когда оффлайн:
- Создать опрос => опрос сохранен на местном уровне; 1.1. Оставить приложение все еще открытым, а затем подключиться к сети => опрос отправлен на сервер; 1.2. Нажмите кнопку «Домой», чтобы приложение запустило фон => Подключить сеть => опрос отправлен на сервер; 1.3. Пользователи принудительно выходят из приложения => Подключить сеть (в этом случае опрос не будет отправлен на сервер) => Открыть приложение (опрос будет синхронизирован с сервером)
Для iOS, это работает для следующих случаев:
Когда он-лайн: Создать опрос, опрос будет синхронизироваться c с сервером (нужно подождать около 5 секунд, прежде чем закрывать приложение. , это будет ошибка при вызове API).
В автономном режиме:
- Создать опрос => опрос сохраняется в локальном режиме. 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;
}
}
Есть какое-нибудь решение, документ или пример кода, которые могут помочь мне решить эту проблему?