Xamarin.Forms移动端:实现应用退出后仍完成任务(如下载)
在Xamarin.Forms中实现应用退出后持续运行的后台任务(如下载)
Xamarin.Forms本身没有统一的跨平台后台任务API,必须针对iOS和Android各自的系统机制实现,以下是具体方案:
Android 平台:前台服务(Foreground Service)
Android 8.0+对后台服务限制严格,只有前台服务能在应用退出后持续运行,且必须显示通知告知用户。
实现步骤:
- 创建后台服务类,继承自
Service,在其中处理下载逻辑并启动前台通知 - 在
AndroidManifest.xml中声明必要权限 - 通过Xamarin.Forms依赖服务启动该服务
代码示例:
后台服务类
[Service] public class DownloadService : Service { public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId) { // 创建前台通知渠道(Android 8.0+必需) if (Build.VERSION.SdkInt >= BuildVersionCodes.O) { var channel = new NotificationChannel("download_channel", "下载任务", NotificationImportance.Default); var notificationManager = (NotificationManager)GetSystemService(NotificationService); notificationManager.CreateNotificationChannel(channel); } // 构建前台通知 var notification = new Notification.Builder(this, "download_channel") .SetContentTitle("下载进行中") .SetContentText("正在完成文件下载") .SetSmallIcon(Resource.Drawable.ic_download) .Build(); // 启动前台服务 StartForeground(1, notification); // 异步执行下载任务 _ = Task.Run(async () => { var downloadUrl = intent.GetStringExtra("url"); await ExecuteDownload(downloadUrl); // 下载完成后停止前台服务和自身 StopForeground(true); StopSelf(); }); return StartCommandResult.Sticky; } private async Task ExecuteDownload(string url) { // 实现具体下载逻辑 using var httpClient = new HttpClient(); var response = await httpClient.GetAsync(url); var filePath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, "downloaded_file.zip"); using var stream = await response.Content.ReadAsStreamAsync(); using var fileStream = new FileStream(filePath, FileMode.Create); await stream.CopyToAsync(fileStream); } public override IBinder OnBind(Intent intent) => null; }
依赖服务接口与实现
共享项目接口:
public interface IDownloadService { void StartDownload(string url); }
Android平台实现:
[assembly: Dependency(typeof(DownloadServiceImplementation))] namespace YourAppName.Droid { public class DownloadServiceImplementation : IDownloadService { public void StartDownload(string url) { var intent = new Intent(Android.App.Application.Context, typeof(DownloadService)); intent.PutExtra("url", url); if (Build.VERSION.SdkInt >= BuildVersionCodes.O) { Android.App.Application.Context.StartForegroundService(intent); } else { Android.App.Application.Context.StartService(intent); } } } }
AndroidManifest.xml权限添加
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- Android 13+必需 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- 如需存储到外部存储 -->
iOS 平台:后台会话(Background Session)
iOS不允许应用退出后长时间运行后台服务,但提供了后台会话机制专门处理网络下载/上传任务,系统会接管任务直至完成。
实现步骤:
- 使用
NSUrlSession创建后台会话 - 实现
INSUrlSessionDownloadDelegate处理下载回调 - 在
AppDelegate中处理后台任务完成的系统回调
代码示例:
后台下载服务实现
[assembly: Dependency(typeof(iOSDownloadService))] namespace YourAppName.iOS { public class iOSDownloadService : IDownloadService, INSUrlSessionDownloadDelegate { private NSUrlSession _backgroundSession; public void StartDownload(string url) { // 创建后台会话配置,标识符需唯一 var config = NSUrlSessionConfiguration.CreateBackgroundSessionConfiguration("com.yourapp.download.session"); _backgroundSession = NSUrlSession.FromConfiguration(config, this, NSOperationQueue.MainQueue); // 创建并启动下载任务 var downloadTask = _backgroundSession.CreateDownloadTask(new NSUrl(url)); downloadTask.Resume(); } [Export("URLSession:downloadTask:didFinishDownloadingToURL:")] public void DidFinishDownloading(NSUrlSession session, NSUrlSessionDownloadTask downloadTask, NSUrl location) { // 将临时文件移动到指定目录 var docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); var destPath = Path.Combine(docPath, "downloaded_file.zip"); var destUrl = NSUrl.FromFilename(destPath); try { NSFileManager.DefaultManager.Move(location, destUrl, out var error); if (error != null) { // 处理文件移动错误 } } catch (Exception ex) { // 捕获异常 } } [Export("URLSession:task:didCompleteWithError:")] public void DidComplete(NSUrlSession session, NSUrlSessionTask task, NSError error) { if (error != null) { // 处理下载错误 } } } }
AppDelegate中添加后台回调处理
public override void HandleEventsForBackgroundUrl(UIApplication application, string sessionIdentifier, Action completionHandler) { // 关联后台会话,确保回调被正确处理 var session = NSUrlSession.FromBackgroundSessionIdentifier(sessionIdentifier); if (session != null) { // 若需要,可在此更新会话委托 } // 必须调用completionHandler告知系统任务处理完成 completionHandler(); }
Xamarin.Forms共享项目调用
在共享代码中通过依赖服务启动下载:
var downloadService = DependencyService.Get<IDownloadService>(); downloadService.StartDownload("https://example.com/your-large-file.zip");
注意事项
- Android:需引导用户将应用加入电池优化白名单,否则系统可能在低电量时终止前台服务;前台通知无法隐藏,必须保持到任务完成。
- iOS:后台会话仅支持HTTP/HTTPS下载,且任务必须是可恢复的;系统会限制后台任务的资源,无法执行计算密集型操作。
内容的提问来源于stack exchange,提问作者Jaafar Dhainy
相关产品推荐
相关产品推荐

