[英]How to run background service in ios forever for syncing of data
嗨,我正在开发一个应用程序,它需要在 Web 服务器上进行同步操作(数据提交和检索)。
用户可以离线提交表单(即将数据存储到设备上的本地数据库)。 并且只要网络可用,后台服务就应该将这些数据提交给 Web 服务器。
后台服务的具体需求如下:
我对 iOS 和 xamarin/monotouch 很陌生,想知道如何实现这一点?
我了解 iOS 中的各种后台模式,例如后台获取、nsurlsession、后台传输等。
我已经尝试实现我认为适合我的情况的后台获取。 但它按自己的时间运行。
还想知道,如果用户杀死了我的应用程序,那么后台提取也会调用并仍然运行我的应用程序?
我的 appdelegate -> PerformFetch 方法中的代码是这样的:
if(networkService.IsNetworkAvailable())
{
if(this.syncDataService.DownloadNewDataFromServer())
{
Console.WriteLine("Data downloaded successfully from server..");
}
if(this.syncDataService.UploadDataToServer())
{
Console.WriteLine("Data submitted successfully to server...");
}
completionHandler(UIBackgroundFetchResult.NewData);
}
else
{
completionHandler(UIBackgroundFetchResult.NoData);
}
更新:最后我以这种方式实现了它(希望它可以对某人有所帮助):
public class LocationUpdatedEventArgs : EventArgs
{
private CLLocation location;
public LocationUpdatedEventArgs(CLLocation location)
{
this.location = location;
}
public CLLocation Location
{
get { return this.location; }
}
}
public class LocationManager
{
private static DateTime lastServiceRun;
private CLLocationManager locMgr;
public LocationManager()
{
this.locMgr = new CLLocationManager();
this.LocationUpdated += this.PrintLocation;
this.locMgr.Failed += (object sender, NSErrorEventArgs e) =>
{
Console.WriteLine("didFailWithError " + e.Error);
Console.WriteLine("didFailWithError coe " + e.Error.Code);
};
}
public event EventHandler<LocationUpdatedEventArgs> LocationUpdated = delegate { };
public static TimeSpan TimeDiff { get; set; }
public CLLocationManager LocMgr
{
get
{
return this.locMgr;
}
}
public void StartLocationUpdates()
{
if (CLLocationManager.LocationServicesEnabled)
{
// sets the accuracy that we want in meters
this.LocMgr.DesiredAccuracy = 1;
//// Location updates are handled differently pre-iOS 6. If we want to support older versions of iOS,
//// we want to do perform this check and let our LocationManager know how to handle location updates.
if (UIDevice.CurrentDevice.CheckSystemVersion(6, 0))
{
this.LocMgr.LocationsUpdated += (object sender, CLLocationsUpdatedEventArgs e) =>
{
//// fire our custom Location Updated event
this.LocationUpdated(this, new LocationUpdatedEventArgs(e.Locations[e.Locations.Length - 1]));
};
}
else
{
//// this won't be called on iOS 6 (deprecated). We will get a warning here when we build.
this.LocMgr.UpdatedLocation += (object sender, CLLocationUpdatedEventArgs e) =>
{
this.LocationUpdated(this, new LocationUpdatedEventArgs(e.NewLocation));
};
}
//// Start our location updates
this.LocMgr.StartUpdatingLocation();
lastServiceRun = DateTime.Now;
// Get some output from our manager in case of failure
this.LocMgr.Failed += (object sender, NSErrorEventArgs e) =>
{
Console.WriteLine(e.Error);
};
}
else
{
//// Let the user know that they need to enable LocationServices
Console.WriteLine("Location services not enabled, please enable this in your Settings");
}
}
/// <summary>
/// The stop updating location.
/// </summary>
public void StopUpdatingLocation()
{
this.locMgr.StopUpdatingLocation();
}
/// <summary>
/// The print location. (This will keep going in the background)
/// </summary>
/// <param name="sender"> The sender. </param>
/// <param name="e"> Location updated event argument </param>
public void PrintLocation(object sender, LocationUpdatedEventArgs e)
{
CLLocation location = e.Location;
Console.WriteLine("Longitude: " + location.Coordinate.Longitude);
Console.WriteLine("Latitude: " + location.Coordinate.Latitude);
var diff = DateTime.Now - lastServiceRun;
TimeDiff = diff;
if (TimeDiff.Minutes == 2)
{
// RunInBackground() is my method which call the service to upload/download data from server
if (this.RunInBackground())
{
lastServiceRun = DateTime.Now;
}
}
}
}
计时器永远不会在后台工作,并且您不能在此方法中添加另一个线程。 DidEnterBackground
用于完成挂起的任务。 这通常会持续大约 30 秒 - 1 分钟。
您可以在此方法中添加循环或添加长时间运行的任务。
在 FinishedLaunching 上的应用程序委托中,您创建计时器,它将在您将设置的时间间隔内调用您的代码
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
...
Timer timer = new Timer(5000); //5000 milisecs - 5 secs
timer.Elapsed += timer_Elapsed;
timer.Start();
...
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
//your code here
}
此外,如果用户将终止您的应用程序,则意味着即使后台获取也不会再调用任何代码
我相信解决您的问题的方法是将您的任务注册为长时间运行的任务。
考虑到你正在使用Xamarin,也有使用Xamarin后台任务一个很好的解释在这里,这可能会更贴近您想要做什么。
此外,请查看应用程序状态和多任务处理以了解应用程序进入后台时发生的情况:“从 applicationDidEnterBackground: 方法返回后,大多数应用程序很快就会进入挂起状态。请求特定后台任务的应用程序(例如播放音乐)或从系统请求一点额外的执行时间可能会继续运行一段时间。”
一般来说,查看苹果开发者网站是一件好事,因为 100% 的 iOS API 都在 Xamarin 中
一个想法,对于iOS。 一种方法是创建一个后台任务调度程序,可能基于 LimitedConcurrencyLevelTaskScheduler ( https://msdn.microsoft.com/en-us/library/ee789351(v=vs.110).aspx ),它将执行您的 IBackgroundTask 作业。 这些作业可以持久化到存储中,并按顺序执行。 例如,如果您想下载大量大文件,您需要一个一个地下载它们并在它们登陆您的设备时在 UI 中显示进度或渲染它们。 然后你用这个调度程序将任何下载任务排入队列,并在它即将死亡时重新启动它:
void StartBackgroundTask() { BackgroundTaskId = UIApplication.SharedApplication.BeginBackgroundTask(() => { // Handle expiration: will happen before reaching 600 secs TaskScheduler.Stop(); UIApplication.SharedApplication.EndBackgroundTask(BackgroundTaskId); // Start again StartBackgroundTask(); }); Task.Run(() => { TaskScheduler = new BackgroundTaskScheduler().Start(); }); }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.