在 xamarin 表单中关闭应用程序时无法显示通知

Posted

技术标签:

【中文标题】在 xamarin 表单中关闭应用程序时无法显示通知【英文标题】:Not able to show notifications when app is closed in xamarin forms 【发布时间】:2021-12-27 04:53:03 【问题描述】:

我正在尝试实现一个后台服务,它会不断地通知我。为此,我使用了警报管理器和广播接收器。这是我的广播接收器代码

[BroadcastReceiver(Enabled = true)]
    [IntentFilter(new string[] PeriodicService.AlarmService, "android.intent.action.BOOT_COMPLETED" , Priority = (int)IntentFilterPriority.LowPriority)]
    public class BackgroundReceiver : BroadcastReceiver
    
        public override void OnReceive(Context context, Intent intent)
        
            PowerManager pm = (PowerManager)context.GetSystemService(Context.PowerService);
            PowerManager.WakeLock wakeLock = pm.NewWakeLock(WakeLockFlags.Partial, "BackgroundReceiver");
            wakeLock.Acquire();
            Device.StartTimer(new TimeSpan(0, 0, 10), () =>
            
                // do something every 60 seconds
                Device.BeginInvokeOnMainThread(() =>
                

                    Toast.MakeText(Android.App.Application.Context, "Hi when app opened", ToastLength.Short).Show();
                    NotificationCenter.NotifyNotificationTapped(intent);
                   
                    var alarmAttributes = new AudioAttributes.Builder()
                                      .SetContentType(AudioContentType.Sonification)
                                      .SetUsage(AudioUsageKind.Alarm)
                                      .Build();

                   // var alarmUri = Android.Net.Uri.Parse("Resources/Audio/AlarmSound.wav");
                    NotificationCenter.Current.Show((notification) => notification
                           .WithScheduleOptions((schedule) => schedule
                           .Build())
                           
                           .WithAndroidOptions((android) => android
                                .WithAutoCancel(true)
                                .WithChannelId("General")
                                
                                .WithPriority(Plugin.LocalNotification.NotificationPriority.High)
                                .Build())
                           .WithiosOptions((ios) => ios
                               .ShouldPlayForegroundSound(true)
                               .Build())
                           .WithReturningData("Dummy Data")
                           .WithTitle("Test Title")
                           .WithDescription("Test Description")
                           .WithNotificationId(100)
                           .Create());
                    Toast.MakeText(Android.App.Application.Context, "HI", ToastLength.Short).Show();
                    MessagingCenter.Send<object, string>(this, "UpdateLabel", "Hello from Android");
                );
                return true; // runs again, or false to stop
            );

            wakeLock.Release();
        
    

这是我的后台服务代码

[Service]
    public class PeriodicService : Service
    
        public override IBinder OnBind(Intent intent)
        
            return null;
        

        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        
            // From shared code or in your PCL
            MessagingCenter.Send<object, string>(this, "UpdateLabel", "Hello from Android");
       
            Device.StartTimer(new TimeSpan(0, 0, 10), () =>
            
                // do something every 60 seconds
                Device.BeginInvokeOnMainThread(() =>
                
                    Toast.MakeText(Android.App.Application.Context, "Hi when app closed", ToastLength.Short).Show();
                  
                );
                return true; // runs again, or false to stop
            );
            return StartCommandResult.Sticky;
        

    

这是我的主要活动代码

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    
       protected override void OnCreate(Bundle savedInstanceState)
    
      

        base.OnCreate(savedInstanceState);


        global::Xamarin.Essentials.Platform.Init(this, savedInstanceState);

        ZXing.Net.Mobile.Forms.Android.Platform.Init();
        

        global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
        global::ZXing.Net.Mobile.Forms.Android.Platform.Init();

        LoadApplication(new App());
        Intent alarmIntent = new Intent(Application.Context, typeof(BackgroundReceiver));
        BackgroundReceiver myreceiver = new BackgroundReceiver();
        RegisterReceiver(myreceiver, new IntentFilter("android.intent.action.BOOT_COMPLETED"));
        //StartService(new Intent(this, typeof(PeriodicService)));
        // CreateNotificationChannel();
        if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
        
            //DispatchNotificationThatServiceIsRunning();
            //StartForegroundService(Intent);
            StartService(new Intent(this, typeof(PeriodicService)));
        
        else
        
            StartService(new Intent(this, typeof(PeriodicService)));
        

       
        //alarmIntent.PutExtra("message", "This is my test message!");
        //alarmIntent.PutExtra("title", "This is my test title!");
        //PendingIntent pendingIntent = PendingIntent.GetBroadcast(Application.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
        //AlarmManager alarmManager = (AlarmManager)Application.Context.GetSystemService(Context.AlarmService);
        //alarmManager.SetAndAllowWhileIdle(AlarmType.RtcWakeup, DateTime.Now.Millisecond + 5000, pendingIntent);

    

这是我在 ma​​nifest

中的代码
<application android:theme="@style/MainTheme" android:usesCleartextTraffic="true" android:allowBackup="false" android:label="myproject">
        <receiver android:name=".BackgroundReceiver" android:enabled="true" android:exported="true" android:process=":remote" android:label="myproject" />
    </application>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.FLASHLIGHT" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>

这是我的我请求许可的代码

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        
            global::Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
            global::ZXing.Net.Mobile.Android.PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);

            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        

我经历了很多解决方案,但没有任何帮助。这些是我浏览过的链接

Android - AlarmManager is not working after app is closed

Alarm Manager not working when app closed

我也尝试使用前台服务,这是我的服务代码

  public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        
            // From shared code or in your PCL
            MessagingCenter.Send<object, string>(this, "UpdateLabel", "Hello from Android");
            
            
                    CreateNotificationChannel();
                    DispatchNotificationThatServiceIsRunning();

            return StartCommandResult.Sticky;
        
        public void DispatchNotificationThatServiceIsRunning()
        
            
            NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(this)
            .SetDefaults((int)NotificationDefaults.All)

            .SetVibrate(new long[]  100, 200, 300, 400, 500, 400, 300, 200, 400 )
            .SetSound(null)

            .SetPriority(NotificationCompat.PriorityHigh)
            .SetAutoCancel(false)
            .SetSmallIcon(Resource.Drawable.notification_icon_background)
            .SetContentTitle("test")
            .SetContentText("service started")
            .SetOngoing(true);
            
            Notification bui = mBuilder.Build();
            NotificationManager notificationManager = (NotificationManager)GetSystemService(NotificationService);
            notificationManager.Notify(0, bui);
            StartForeground(121, bui);
            
        

        public void CreateNotificationChannel()
        
            if (Build.VERSION.SdkInt < BuildVersionCodes.O)
            

                return;
            

            var channelName = "Notification_Channel";
            var channelDescription = "Foreground Notification";
            var channel = new NotificationChannel("10121", channelName, NotificationImportance.High)
            
                Description = channelDescription
            ;

            var notificationManager = (NotificationManager)GetSystemService(NotificationService);
            notificationManager.CreateNotificationChannel(channel);
        

到目前为止,我在应用设置中获得了通知渠道,但通知没有显示给我。我正在使用 Redmi note 8 设备,并且我的目标 android 版本是 Android 11.0(API 级别 30)。我已经浏览了满足我要求的应用程序 StepSetGo 你可以发现在 Playstore 中你可以看到 应用程序持续显示通知 即使 应用程序被杀死,它记录了没有互联网的步数。我已经为此应用程序授予了相同的权限,例如 自动启动和无电池限制,但它仍然无法正常工作。我不知道如何解决这个问题有什么建议吗?

【问题讨论】:

也许我错过了...您的代码在哪里检查在运行时您的应用程序是否实际上已获得用户的权限,如果没有,是否对 Android 进行适当的调用,这将打开一个标准的 Android 对话框,用户可以接受或拒绝? docs.microsoft.com/en-us/xamarin/android/app-fundamentals/… @ToolmakerSteve 我已经在我请求许可的地方添加了代码。 到目前为止一切顺利。现在查看Checking Permissions,并检查返回的status @ToolmakerSteve 是的,权限很好,但应用程序在关闭时仍然没有运行。 可以,可以使用FCM来实现这个功能。 【参考方案1】:

广播接收器将与应用程序一起死亡。我会使用服务来启动广播接收器并让它直接与服务对话。

为您服务: MyReceiver myreceiver = new MyReceiver(this); RegisterReceiver(myreceiver, new IntentFilter("com.example.MyReceiver");

在您的接收器中:

service.Notify("现在该起床了!");

另外,我注意到您的服务没有永久运行的通知。它将被操作系统杀死。

在您的服务中: StartForeground(intID, 通知);

【讨论】:

在我的代码中,我正在使用一个名为 PeriodicService 的服务,这很好,或者我应该创建一个单独的服务。您的回答似乎是相关的,请您详细说明。 您创建的每个服务都必须有一个永久通知。如果您愿意,您可以创建更多。但我不明白您的 PeriodicService 的目的。我会用它来保持接收器运行并在应用程序发送到后台或关闭时显示通知。 我尝试了您的建议,但对我不起作用。我也编辑了我的问题,请看一下。 当应用死机时你想做的一切都必须在服务中,即你的 PeriodicService 中。如果应用程序死了,运行您的代码的线程将停止。服务必须做所有事情。就我而言,我需要一项服务来捕获活动更改。我正在启动服务,从服务中启动接收器。收到后,我告诉服务人员当时该做什么。您的服务有一个通知,但它没有反应或做任何事情的逻辑。它只是存在。将服务视为可以做事的独立实体,无论应用程序的状态如何。 如果您有链接或示例。这将是有益的。

以上是关于在 xamarin 表单中关闭应用程序时无法显示通知的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Interface Builder 中关闭键盘,因为视图控制器不会显示 doneEditing:

在 SplitContainer 中关闭 mdi 子项

如何让线程等待 JFrame 在 Java 中关闭?

UIImageView 对齐在初始显示时在 tableview 单元格中关闭,但之后没有

在 watchOS 2 中关闭屏幕时无法获取加速度计和心率数据

如何使用 VBA 在 Access 中关闭单个表单实例?