Как создать фоновую службу в .NET Maui

Я новичок в разработке мобильных приложений и изучаю .NET Maui. Приложение, которое я создаю, должно прослушивать события акселерометра и отправлять уведомление в веб-службу, если события соответствуют определенным критериям. Немного, с которым я борюсь, - это то, как запустить приложение в фоновом режиме, то есть без видимого пользовательского интерфейса, без перехода в спящий режим, поскольку я бы хотел, чтобы пользователь полностью закрыл пользовательский интерфейс. Поэтому я думаю, что приложение должно работать как своего рода служба с возможностью отображения пользовательского интерфейса при необходимости - как это можно сделать?

2 ответа

я знаю, что это было какое-то время, но опубликую ответ для будущих пользователей!

Во-первых, нам нужно понять, что фоновые службы зависят от того, какую платформу мы используем (спасибо, Джейсон). И я сосредоточусь на ANDROID, основанном на документации Xamarin (спасибо, Эли), адаптированной для Мауи.

Так как мы работаем с ANDROID , на MauiProgram добавим следующее:

         /// Add dependecy injection to main page
   builder.Services.AddSingleton<MainPage>();
 
#if ANDROID
   builder.Services.AddTransient<IServiceTest, DemoServices>();
#endif

И мы создаем наш интерфейс для DI, который предоставляет нам методы для запуска и остановки службы переднего плана.

      public interface IServiceTest
{
    void Start();
    void Stop();
}

Затем перед кодом платформы нам нужно добавить разрешения Android в AndroidManifest.xml :

      <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Основное действие Android

      public class MainActivity : MauiAppCompatActivity
{
   //set an activity on main application to get the reference on the service
   public static MainActivity ActivityCurrent { get; set; }
   public MainActivity()
   {
      ActivityCurrent = this;
   }
}

И, наконец, мы создаем нашу службу переднего плана Android. Проверьте комментарии ниже. Также в документах xamarin показаны различные свойства построителя уведомлений.

      [Service]
public class DemoServices : Service, IServiceTest //we implement our service (IServiceTest) and use Android Native Service Class
{
   public override IBinder OnBind(Intent intent)
   {
      throw new NotImplementedException();
   }
   
   [return: GeneratedEnum]//we catch the actions intents to know the state of the foreground service
   public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
   {
      if (intent.Action == "START_SERVICE")
      {
         RegisterNotification();//Proceed to notify
      }
      else if (intent.Action == "STOP_SERVICE")
      {
         StopForeground(true);//Stop the service
         StopSelfResult(startId);
      }
      
      return StartCommandResult.NotSticky;
   }
    
   //Start and Stop Intents, set the actions for the MainActivity to get the state of the foreground service
   //Setting one action to start and one action to stop the foreground service
   public void Start()
   {
      Intent startService = new Intent(MainActivity.ActivityCurrent, typeof(DemoServices));
      startService.SetAction("START_SERVICE");
      MainActivity.ActivityCurrent.StartService(startService);
   }
    
   public void Stop()
   {
      Intent stopIntent = new Intent(MainActivity.ActivityCurrent, this.Class);
      stopIntent.SetAction("STOP_SERVICE");
      MainActivity.ActivityCurrent.StartService(stopIntent);
   }
    
   private void RegisterNotification()
   {
      NotificationChannel channel = new NotificationChannel("ServiceChannel", "ServiceDemo", NotificationImportance.Max);
      NotificationManager manager = (NotificationManager)MainActivity.ActivityCurrent.GetSystemService(Context.NotificationService);
      manager.CreateNotificationChannel(channel);
      Notification notification = new Notification.Builder(this, "ServiceChannel")
         .SetContentTitle("Service Working")
         .SetSmallIcon(Resource.Drawable.abc_ab_share_pack_mtrl_alpha)
         .SetOngoing(true)
         .Build();
    
      StartForeground(100, notification);
   }
}

Теперь у нас есть служба переднего плана, работающая на Android, которая показывает уведомление («Служба работает»). Каждый раз, когда он начинается. Я делаю службу переднего плана для показа сообщений, чтобы лучше видеть ее во время тестирования, в вашем случае предполагается закрытие приложения, если это то, что вы хотите, но функционирование это то же самое.

Итак, работая с нашей фоновой службой, остался только способ вызвать ее, поэтому на нашей главной странице (в качестве примера) я сделаю следующее:

MainPage.xaml

      <VerticalStackLayout>
   <Label
      Text="Welcome to .NET Multi-platform App UI"
      FontSize="18"
      HorizontalOptions="Center" />
    
   <Button
      x:Name="CounterBtn"
      Text="start Services"
      Clicked="OnServiceStartClicked"
      HorizontalOptions="Center" />
    
   <Button Text="Stop Service" Clicked="Button_Clicked"></Button>
    
</VerticalStackLayout>

MainPage.xaml.cs

      public partial class MainPage : ContentPage
{
   IServiceTest Services;

   public MainPage(IServiceTest Services_)
   {
      InitializeComponent();
      ToggleAccelerometer();
      Services = Services_;
   }

   //method to start manually foreground service
   private void OnServiceStartClicked(object sender, EventArgs e)
   {
      Services.Start();
   }

   //method to stop manually foreground service
   private void Button_Clicked(object sender, EventArgs e)
   {
      Services.Stop();
   }
   
   //method to work with accelerometer
   public void ToggleAccelerometer()
   {
      if (Accelerometer.Default.IsSupported)
      {
         if (!Accelerometer.Default.IsMonitoring)
         {
            Accelerometer.Default.ReadingChanged += Accelerometer_ReadingChanged;
            Accelerometer.Default.Start(SensorSpeed.UI);
         }
         else
         {
            Accelerometer.Default.Stop();
            Accelerometer.Default.ReadingChanged -= Accelerometer_ReadingChanged;
         }
      }
   }
   
   //on accelerometer property change we call our service and it would send a message
   private void Accelerometer_ReadingChanged(object sender, AccelerometerChangedEventArgs e)
   {
      Services.Start(); //this will never stop until we made some logic here
   }
}

Это длинный ответ, и было бы здорово иметь больше официальной документации по этому поводу! Надеюсь, поможет! Если кто-нибудь может предоставить больше информации о IOS, Windows, MacCatalyst, было бы здорово!

Моя репутация слишком низкая, чтобы добавлять комментарии

Чтобы добавить к ответу Леандро, вы должны указать использование в правильной ОС платформы. В противном случае вы не сможете использовать IntelliSense для добавления использований.

Выберите ОС Android в раскрывающемся списке, показанном на этом изображении:Выбор раскрывающегося списка ОС Android.

Теперь вы можете использовать IntelliSense для добавления файлов using.

      using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
Другие вопросы по тегам