【发布时间】:2020-01-09 16:14:55
【问题描述】:
我正在开发一个允许用户输入调查的应用程序。应用程序可以在离线/在线时工作。
概念如下:
- 在线情况下:当用户进入调查并点击提交按钮时,应用程序将调用api(使用
httpClient)将调查信息发送到服务器。 - 离线情况下:当用户进入调查并点击提交按钮时,应用程序会将调查信息保存在本地。移动设备连接网络后,会调用api将调查信息从本地发送到服务器。
工作流程:
-
对于 android,它适用于以下情况:
在线时: - 创建调查,调查将发送到服务器。
离线时:
- 创建调查 => 调查保存在本地; 1.1。保持应用程序仍在打开,然后连接网络 => 调查已发送到服务器; 1.2.触摸主页按钮,让应用程序在后台运行 => 连接网络 => 调查已发送到服务器; 1.3.用户强制退出应用 => 连接网络(在这种情况下,调查不会发送到服务器)=> 打开应用(调查将同步到服务器)
-
对于 iOS,它适用于以下情况:
在线时:创建调查,调查将同步到服务器(需要等待大约5秒才能关闭应用程序。因为如果立即关闭,调用api时会出错)。
离线时:
- 创建调查 => 调查保存在本地。 1.1。保持应用程序仍在打开,然后连接网络 => 调查已发送到服务器; 1.2.触摸主页按钮,让应用程序在后台运行 => 连接网络(在这种情况下,调查不会发送到服务器)=> 打开应用程序(调查将被发送到服务器); 1.3.用户强制退出应用 => 连接网络(在这种情况下,调查不会发送到服务器)=> 打开应用(调查将发送到服务器)
所以我发现在 Android 上一切正常。 但是,如果应用程序在 iOS 上运行后台,则会出现问题。只有当用户打开应用程序时,调查才会发送到服务器。 对于 iOS,我使用的是静默通知。当应用程序在后台运行时,将每 5 分钟向应用程序推送通知以触发调用 API(将调查发送到服务器)。目前,当应用收到通知时,应用可以调用API,但调用api时出错。
- 我使用我的 iPhone 并在 Facebook Messenger 上进行了测试,以防我在离线时发送消息,然后触摸主页按钮运行后台(不是强制退出应用程序)。连接网络后,无需打开应用即可发送消息。
这是错误:
NSLocalizedDescription=网络连接丢失。, NSErrorFailingURLStringKey=[URL],NSErrorFailingURLKey=[URL], _kCFStreamErrorDomainKey=4} --- 内部异常堆栈跟踪结束 --- 在 System.Net.Http.NSUrlSessionHandler.SendAsync(System.Net.Http.HttpRequestMessage 请求, System.Threading.CancellationToken cancelToken) 在 :0 在 System.Net.Http.HttpClient.SendAsyncWorker (System.Net.Http.HttpRequestMessage 请求, System.Net.Http.HttpCompletionOption 完成选项, System.Threading.CancellationToken cancelToken) 在 :0 在 SurveyApp.Service.RestClient.PostAsync[T,TP] (System.String url, TP t,System.Nullable 1[T] 令牌) 在 :0 在 SurveyApp.Service.SyncService.Push (System.Collections.Generic.IList 1[T] 同步) 在:0 在 SurveyApp.Service.SyncService.PushSurveys () 在 :0 ","System.Net.Http.HttpRequestException 网络连接是 丢失。在 System.Net.Http.NSUrlSessionHandler.SendAsync (System.Net.Http.HttpRequestMessage 请求, System.Threading.CancellationToken cancelToken) 在 :0 在 System.Net.Http.HttpClient.SendAsyncWorker (System.Net.Http.HttpRequestMessage 请求, System.Net.Http.HttpCompletionOption 完成选项, System.Threading.CancellationToken cancelToken) 在 :0 在 SurveyApp.Service.RestClient.PostAsync[T,TP] (System.String url, TP t,System.Nullable 1[T] 令牌) 在 :0 在 SurveyApp.Service.SyncService.Push (System.Collections.Generic.IList 1[T] 同步) 在:0 在 SurveyApp.Service.SyncService.PushSurveys () 在 :0 Foundation.NSErrorException 错误域=NSURLErrorDomain 代码=-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;
}
}
是否有任何解决方案、文档或示例代码可以帮助我解决此问题?
【问题讨论】:
-
您能否在调用 SyncData() 之前尝试添加一点延迟;如this thread中所述?那里的人正试图做和你一样的事情。还要确保您已启用后台模式(后台获取和远程通知)。
-
感谢您的回答,杰克。 - 我试过但似乎不起作用。 - 还有一个问题,在我禁用网络并再次启用网络后,应用程序无法接收静默通知。只有当我再次打开应用程序(前台)时它才会收到,然后我进入后台后它也可以收到。你知道为什么吗?
-
您的应用程序在进入后台后似乎挂起,并且在再次启用网络后没有重新连接。
-
感谢您的支持,非常感谢,杰克。
-
没问题,你找到解决办法了吗?