如何在Xamarin应用中实现Google Play样式通知(含进度与取消功能)
Xamarin 带下载进度与交互的通知实现方案
由于Xamarin是跨平台框架,Android和iOS的通知系统实现逻辑差异较大,下面分平台说明具体实现方式:
Android 端实现
1. 创建通知通道(Android 8.0+ 必需)
private void CreateDownloadNotificationChannel() { if (Build.VERSION.SdkInt >= BuildVersionCodes.O) { var channel = new NotificationChannel( "DownloadChannel", "下载通知", NotificationImportance.Default) { Description = "显示下载进度与操作按钮" }; var notificationManager = (NotificationManager)GetSystemService(NotificationService); notificationManager.CreateNotificationChannel(channel); } }
2. 构建带进度条、取消按钮的通知
public Notification BuildDownloadNotification(int progress, string downloadId) { // 点击通知跳转至详情页的意图 var detailIntent = new Intent(this, typeof(DownloadDetailActivity)); detailIntent.PutExtra("DownloadId", downloadId); var detailPendingIntent = PendingIntent.GetActivity( this, 0, detailIntent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable); // 取消按钮的触发意图 var cancelIntent = new Intent(this, typeof(DownloadCancelReceiver)); cancelIntent.PutExtra("DownloadId", downloadId); var cancelPendingIntent = PendingIntent.GetBroadcast( this, 1, cancelIntent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable); var builder = new NotificationCompat.Builder(this, "DownloadChannel") .SetContentTitle("正在下载") .SetContentText("文件下载中") .SetSmallIcon(Resource.Drawable.ic_download) .SetContentIntent(detailPendingIntent) .AddAction(Resource.Drawable.ic_cancel, "取消", cancelPendingIntent) .SetProgress(100, progress, progress == 0); // progress为0时显示模糊动画进度 // 添加动画图标(需提前准备AnimatedVectorDrawable资源) if (progress == 0) { var animatedDrawable = Resources.GetDrawable(Resource.Drawable.animated_download, Theme); builder.SetLargeIcon(((BitmapDrawable)animatedDrawable).Bitmap); } return builder.Build(); }
3. 实现取消操作的广播接收器
[BroadcastReceiver(Enabled = true)] public class DownloadCancelReceiver : BroadcastReceiver { public override void OnReceive(Context context, Intent intent) { var downloadId = intent.GetStringExtra("DownloadId"); // 执行取消下载逻辑(比如终止下载任务、更新本地状态) var downloadManager = DownloadManager.FromContext(context); downloadManager.Remove(long.Parse(downloadId)); // 关闭通知 var notificationManager = (NotificationManager)context.GetSystemService(Context.NotificationService); notificationManager.Cancel(1); // 1为通知ID,需与创建时保持一致 } }
4. 实时更新下载进度
在下载任务的回调方法中调用:
private void UpdateNotificationProgress(int progress, string downloadId) { var notificationManager = (NotificationManager)GetSystemService(NotificationService); var notification = BuildDownloadNotification(progress, downloadId); notificationManager.Notify(1, notification); }
iOS 端实现
1. 注册通知权限与交互类别
在AppDelegate的FinishedLaunching方法中初始化:
public override bool FinishedLaunching(UIApplication app, NSDictionary options) { // 请求通知权限 UNUserNotificationCenter.Current.RequestAuthorization( UNAuthorizationOptions.Alert | UNAuthorizationOptions.Sound, (granted, error) => { if (granted) { DispatchQueue.MainQueue.InvokeOnMainThread(() => UIApplication.SharedApplication.RegisterForRemoteNotifications()); } }); // 创建带取消按钮的通知类别 var cancelAction = UNNotificationAction.FromIdentifier( "CancelDownload", "取消", UNNotificationActionOptions.None); var downloadCategory = UNNotificationCategory.FromIdentifier( "DownloadCategory", new[] { cancelAction }, new string[] { }, UNNotificationCategoryOptions.None); UNUserNotificationCenter.Current.SetNotificationCategories(new NSSet<UNNotificationCategory>(downloadCategory)); return true; }
2. 构建带进度的通知
public void SendDownloadNotification(string downloadId, int progress) { var content = new UNMutableNotificationContent(); content.Title = progress < 100 ? "正在下载" : "下载完成"; content.Subtitle = progress < 100 ? "文件下载中" : "文件已就绪"; content.CategoryIdentifier = "DownloadCategory"; content.UserInfo = new NSDictionary("DownloadId", downloadId); content.Progress = progress / 100.0f; // 添加动画附件(支持GIF/本地视频,需传入本地文件路径) var gifPath = NSBundle.MainBundle.PathForResource("download_anim", "gif"); if (!string.IsNullOrEmpty(gifPath)) { var attachment = UNNotificationAttachment.FromIdentifier( "anim_attachment", NSUrl.FromFilename(gifPath), null, out var error); if (error == null) content.Attachments = new[] { attachment }; } // 立即触发通知 var trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(0.1, false); var request = UNNotificationRequest.FromIdentifier( $"Download_{downloadId}", content, trigger); UNUserNotificationCenter.Current.AddNotificationRequest(request, null); }
3. 处理通知交互
实现UNUserNotificationCenterDelegate的回调方法:
public override void DidReceiveNotificationResponse( UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler) { var downloadId = response.Notification.Request.Content.UserInfo["DownloadId"].ToString(); if (response.ActionIdentifier == "CancelDownload") { // 执行取消下载逻辑 CancelDownloadTask(downloadId); center.RemoveDeliveredNotifications(new[] { response.Notification.Request.Identifier }); } else if (response.ActionIdentifier == UNNotificationDefaultActionIdentifier) { // 跳转至详情页 var storyboard = UIStoryboard.FromName("Main", null); var detailVC = storyboard.InstantiateViewController(nameof(DownloadDetailVC)) as DownloadDetailVC; detailVC.DownloadId = downloadId; UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(detailVC, true, null); } completionHandler(); } private void CancelDownloadTask(string downloadId) { // 终止下载任务的具体逻辑(比如停止NSURLSession任务) }
4. 更新下载进度
iOS通知无法直接修改,需删除旧通知后重新发送:
public void UpdateDownloadProgress(string downloadId, int progress) { UNUserNotificationCenter.Current.RemoveDeliveredNotifications(new[] { $"Download_{downloadId}" }); SendDownloadNotification(downloadId, progress); }
跨平台统一调用
可以在共享项目中定义接口,通过依赖注入实现跨平台调用:
public interface IDownloadNotificationService { void Initialize(); void UpdateProgress(string downloadId, int progress); void CancelNotification(string downloadId); }
在Android和iOS项目中分别实现该接口,封装上述原生逻辑即可。
内容的提问来源于stack exchange,提问作者Jaafar Dhainy
相关产品推荐
相关产品推荐

