如何通过推送通知更新Android Widget?Xamarin.Forms实现咨询
问题:收到Firebase推送时自动更新Android Widget(进程被杀时也生效)
我希望在收到推送通知时更新我的Android Widget(即使应用进程已被杀死),请问是否有可行的实现方式,还是只能通过点击Widget来更新?
目前我已在Xamarin.Forms项目中集成了Firebase推送通知,Android项目中的Application.cs代码如下:
using Android.App; using Android.OS; using Android.Runtime; using Plugin.FirebasePushNotification; using System; namespace appslovo.Droid { [Application] public class MainApplication : Application { public MainApplication(IntPtr handle, JniHandleOwnership transer) : base(handle, transer) { } public override void OnCreate() { base.OnCreate(); //Set the default notification channel for your app when running Android Oreo if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O) { //Change for your default notification channel id here FirebasePushNotificationManager.DefaultNotificationChannelId = "FirebasePushNotificationChannel"; //Change for your default notification channel name here FirebasePushNotificationManager.DefaultNotificationChannelName = "New posts"; FirebasePushNotificationManager.DefaultNotificationChannelImportance = NotificationImportance.Max; } //If debug you should reset the token each time. #if DEBUG // FirebasePushNotificationManager.Initialize(this, true); #else FirebasePushNotificationManager.Initialize(this, false); #endif //Handle notification when app is closed here CrossFirebasePushNotification.Current.OnNotificationReceived += (s, p) => { // *??????probably i need to write something there?????????* }; } } }
另外,我在Android文件夹中有Widget.cs文件(默认通过点击更新):
using System; using System.Linq; using System.Net.Http; using System.Threading.Tasks; using Android.App; using Android.Appwidget; using Android.Content; using System.Configuration; using System.IO; using Xamarin.Essentials; using Android.Runtime; using Android.Content.PM; using System.Collections.Specialized; using Android.Widget; using System.ComponentModel; using System.Text.RegularExpressions; namespace appslovo.Droid { [BroadcastReceiver(Label = "Widget", Exported =true)] [IntentFilter(new string[] { "android.appwidget.action.APPWIDGET_UPDATE" })] [IntentFilter(new string[] { "android.intent.action.BOOT_COMPLETED" })] [IntentFilter(new[] { Intent.ActionTimeTick })] [IntentFilter(new[] { Intent.ActionApplicationRestrictionsChanged })] [IntentFilter(new string[] { "android.intent.action.TIME_CHANGED" })] [IntentFilter(new [] { Intent.ActionAppError })] [MetaData("android.appwidget.provider", Resource = "@xml/appwidgetprovider")] public class AppWidget : AppWidgetProvider { public async override void OnUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { var me = new ComponentName(context_wdgt, Java.Lang.Class.FromType(typeof(AppWidget)).Name); appWidgetManager_wdgt.UpdateAppWidget(me, BuildRemoteViews(context_wdgt, appWidgetIds_wdgt, ss, nn, tt)); } ... }
我认为应该在CrossFirebasePushNotification.Current.OnNotificationReceived += (s, p) => {}中调用Widget的更新方法,但不知道具体如何实现。
解决方案
完全可以实现推送触发Widget更新,无需依赖点击操作,具体步骤如下:
1. 给Widget添加自定义更新广播Action
在AppWidget类的IntentFilter中添加一个自定义Action,用于触发Widget更新:
[BroadcastReceiver(Label = "Widget", Exported =true)] [IntentFilter(new string[] { "android.appwidget.action.APPWIDGET_UPDATE" })] // 保留原有其他IntentFilter... // 添加自定义更新Action [IntentFilter(new string[] { "com.appslovo.droid.UPDATE_WIDGET" })] [MetaData("android.appwidget.provider", Resource = "@xml/appwidgetprovider")] public class AppWidget : AppWidgetProvider { // 定义常量方便全局调用 public const string UpdateWidgetAction = "com.appslovo.droid.UPDATE_WIDGET"; // ... }
2. 在Firebase推送回调中发送自定义广播
在MainApplication的OnNotificationReceived事件中,发送自定义广播触发Widget更新:
CrossFirebasePushNotification.Current.OnNotificationReceived += (s, p) => { // 创建触发Widget更新的Intent var updateIntent = new Intent(AppWidget.UpdateWidgetAction); updateIntent.SetPackage(PackageName); // 指定包名,确保广播仅发给自身App,避免被系统拦截 // 发送广播 SendBroadcast(updateIntent); };
3. 在Widget中处理自定义广播
重写AppWidgetProvider的OnReceive方法,判断广播Action并执行更新逻辑:
public override void OnReceive(Context context, Intent intent) { base.OnReceive(context, intent); // 判断是否为自定义更新广播 if (intent.Action == UpdateWidgetAction) { var appWidgetManager = AppWidgetManager.GetInstance(context); // 获取当前所有该Widget的实例ID var componentName = new ComponentName(context, Java.Lang.Class.FromType(typeof(AppWidget)).Name); int[] appWidgetIds = appWidgetManager.GetAppWidgetIds(componentName); // 调用OnUpdate执行更新 OnUpdate(context, appWidgetManager, appWidgetIds); } }
4. 修正Widget中OnUpdate的变量问题
你原代码中的context_wdgt、appWidgetManager_wdgt属于未定义变量,直接使用方法参数中的实例即可:
public async override void OnUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // 替换为你实际的BuildRemoteViews逻辑,确保参数正确 var remoteViews = BuildRemoteViews(context, appWidgetIds, ss, nn, tt); var componentName = new ComponentName(context, Java.Lang.Class.FromType(typeof(AppWidget)).Name); appWidgetManager.UpdateAppWidget(componentName, remoteViews); }
关键注意事项
- Android 8.0+后台限制:必须通过
SetPackage(PackageName)指定广播接收方,否则系统会拦截后台广播。 - 推送优先级:确保Firebase推送消息设置为
高优先级(priority: high),这样即使App进程被杀,系统也会唤醒App处理推送,进而触发Widget更新。 - 权限说明:无需额外申请权限,因为我们发送的是应用内定向广播。
内容的提问来源于stack exchange,提问作者демид владимиров
相关产品推荐
相关产品推荐

