最近几天,我一直在努力让iOS应用在后台运行时能ping通我的API。
我已经遍历了Apple的iOS框架上的所有文档以及Xamarin文档。看起来很简单,设置了计划的刷新任务,然后提交URL请求。
后台任务标识符位于info.plist中,并且后台处理和获取功能已打开。
我已经在当前正在使用的应用上尝试过此操作,并且还为此目的专门设置了一个测试应用。 我已经尝试了是否使用NSOperation和NSOperatonQueue。 在极少数情况下,我会在MS App Center的事件日志中看到计划任务,因此要触发该任务,但是只有一次且不再重复。
首先,我尝试了后台获取功能,但似乎没有被触发,因此我切换到iOS 13后台任务。
我正在MacOS 11中(也在Windows 10的VS2019中)在Visual Studio 2019中进行开发,但是在调试XCode中的应用程序过程时遇到了麻烦。
我正在提供指向我在GitHub中的测试项目存储库的链接。 https://github.com/sigthor/background.ping
相关代码位于AppDelegate.cs和PingOperation.cs
public readonly NSUrlSessionConfiguration urlSessionConfiguration = null;
private readonly NSUrlSession urlSession = null;
private readonly string RefreshTaskId = "com.bgtest.ios.background-test.refresh";
public AppDelegate()
{
urlSessionConfiguration =
NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration("com.bgtest.ios.background-test");
urlSession = NSUrlSession.FromConfiguration(urlSessionConfiguration);
}
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.SetFlags("CollectionView_Experimental");
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
BGTaskScheduler.Shared.Register(RefreshTaskId, null, task => HandleAppRefresh(task as BGAppRefreshTask));
return base.FinishedLaunching(app, options);
}
public override void DidEnterBackground(UIApplication uiApplication)
{
ScheduleAppRefresh();
base.DidEnterBackground(uiApplication);
}
private void HandleAppRefresh(BGAppRefreshTask task)
{
Debug.WriteLine("HandleAppRefresh started");
ScheduleAppRefresh();
var queue = new NSOperationQueue();
queue.MaxConcurrentOperationCount = 1;
var pingOperation = new PingOperation(0, 0, "205558e0-f226-446d-a769-aaceb3b2a880", urlSession);
task.ExpirationHandler = () =>
{
queue.CancelAllOperations();
};
pingOperation.CompletionBlock = () =>
{
Debug.WriteLine("Ping operation completed");
task.SetTaskCompleted(!pingOperation.IsCancelled);
};
queue.AddOperation(pingOperation);
}
private void ScheduleAppRefresh()
{
Debug.WriteLine("Scheduling ping task");
var request = new BGAppRefreshTaskRequest(RefreshTaskId)
{
EarliestBeginDate = (NSDate)DateTime.Now.AdMinutes(5)
};
BGTaskScheduler.Shared.Submit(request, out NSError error);
if (error != null)
{
throw new Exception(error.LocalizedDescription);
}
}
public class PingOperation : NSOperation
{
...
public override void Start()
{
Debug.WriteLine("Ping operation started");
WillChangeValue("IsExecuting");
isExecuting = true;
DidChangeValue("IsExecuting");
if (IsCancelled)
{
Finish(false);
return;
}
Debug.WriteLine("UrlSession request created");
var request = CreatePingRequest();
dataTask = session.CreateDataTask(request);
Finish(true);
}
public void Finish(bool result)
{
if (IsExecuting)
{
return;
}
WillChangeValue("IsExecuting");
WillChangeValue("IsFinished");
isExecuting = false;
this.result = result;
dataTask.Dispose();
dataTask = null;
DidChangeValue("IsExecuting");
DidChangeValue("IsFinished");
}
private NSUrlRequest CreatePingRequest()
{
var url = GeneratePingUrl(userId);
var req = new NSMutableUrlRequest(NSUrl.FromString(url));
req.HttpMethod = "POST";
req.CachePolicy = NSUrlRequestCachePolicy.ReloadIgnoringCacheData;
var content = JsonConvert.SerializeObject(new
{
Long = longitude,
Lat = latitude
});
req.Body = content;
return req;
}
...
}
Ps。我还尝试仅在调度程序之外手动触发任务。 NSUrlRequset已创建,但请求似乎从未发出过。
我们非常感谢您的帮助。