如何创建 Xamarin 前台服务

Dav*_*rpe 4 c# android visual-studio xamarin.android xamarin

尝试创建我的第一个 Xamarin 前台服务,但找不到合适的示例。Microsoft 文档中的示例似乎不完整或使用了折旧的 Notification.Builder:

https://docs.microsoft.com/en-us/xamarin/android/app-fundamentals/services/foreground-services

https://docs.microsoft.com/en-us/samples/xamarin/monodroid-samples/applicationfundamentals-servicesamples-foregroundservicedemo/

我发现了一个似乎是最新的代码示例,但我正在努力通过查看代码来破译它的工作原理:

https://docs.microsoft.com/en-us/samples/xamarin/monodroid-samples/android-o-androidplaylocation-locupdfgservice/

谁能给我一个如何创建基本前台服务的例子?

Dav*_*rpe 10

我终于拼凑了一个答案。以下是任何发现自己在这里的人的示例:

创建一个依赖服务,以便您可以从您的共享代码调用您的启动/停止服务方法。

制作界面:

public interface IAndroidService
    {
        void StartService();

        void StopService();
    }
Run Code Online (Sandbox Code Playgroud)

在使用该接口的 android 项目中实现一个类。记得添加程序集引用。

[assembly: Xamarin.Forms.Dependency(typeof(AndroidServiceHelper))]

namespace YourNameSpace.Droid
{
    internal class AndroidServiceHelper : IAndroidService
    {
        private static Context context = global::Android.App.Application.Context;

        public void StartService()
        {
            var intent = new Intent(context, typeof(DataSource));

            if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
            {
                context.StartForegroundService(intent);
            }
            else
            {
                context.StartService(intent);
            }
        }

        public void StopService()
        {
            var intent = new Intent(context, typeof(DataSource));
            context.StopService(intent);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们做了几乎相同的事情(创建接口并在 android 项目中的类中实现)来创建前台服务所需的通知:

创建通知的界面

public interface INotification
    {
        Notification ReturnNotif();
    }
Run Code Online (Sandbox Code Playgroud)

在 android 项目中创建一个实现 INotification 的类,这样我们就可以创建并返回一个通知对象,我们需要启动一个前台服务。记得添加程序集引用:

[assembly: Xamarin.Forms.Dependency(typeof(NotificationHelper))]

namespace MetroAlarmHandlerMobile.Droid
{
    internal class NotificationHelper : INotification
    {
        private static string foregroundChannelId = "9001";
        private static Context context = global::Android.App.Application.Context;


        public Notification ReturnNotif()
        {
            // Building intent
            var intent = new Intent(context, typeof(MainActivity));
            intent.AddFlags(ActivityFlags.SingleTop);
            intent.PutExtra("Title", "Message");

            var pendingIntent = PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.UpdateCurrent);

            var notifBuilder = new NotificationCompat.Builder(context, foregroundChannelId)
                .SetContentTitle("Your Title")
                .SetContentText("Main Text Body")
                .SetSmallIcon(Resource.Drawable.MetroIcon)
                .SetOngoing(true)
                .SetContentIntent(pendingIntent);

            // Building channel if API verion is 26 or above
            if (global::Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.O)
            {
                NotificationChannel notificationChannel = new NotificationChannel(foregroundChannelId, "Title", NotificationImportance.High);
                notificationChannel.Importance = NotificationImportance.High;
                notificationChannel.EnableLights(true);
                notificationChannel.EnableVibration(true);
                notificationChannel.SetShowBadge(true);
                notificationChannel.SetVibrationPattern(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 });

                var notifManager = context.GetSystemService(Context.NotificationService) as NotificationManager;
                if (notifManager != null)
                {
                    notifBuilder.SetChannelId(foregroundChannelId);
                    notifManager.CreateNotificationChannel(notificationChannel);
                }
            }

            return notifBuilder.Build();
        }
}
Run Code Online (Sandbox Code Playgroud)

创建一个从 Service 继承和覆盖的类。这是在您的共享代码中创建的类,我们将在其中调用要在前台服务上运行的方法。

public class DataSource : Service
    {

        public override IBinder OnBind(Intent intent)
        {
            return null;
        }

        public const int ServiceRunningNotifID = 9000;

        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
            Notification notif = DependencyService.Get<INotification>().ReturnNotif();
            StartForeground(ServiceRunningNotifID, notif);

            _ = DoLongRunningOperationThings();

            return StartCommandResult.Sticky;
        }

        public override void OnDestroy()
        {
            base.OnDestroy();
        }

        public override bool StopService(Intent name)
        {
            return base.StopService(name);
        }


}
Run Code Online (Sandbox Code Playgroud)

您现在可以使用以下代码在共享代码中的任何位置使用依赖服务启动和停止前台服务:

开始

DependencyService.Get<IAndroidService>().StartService();
Run Code Online (Sandbox Code Playgroud)

停止

DependencyService.Get<IAndroidService>().StopService();
Run Code Online (Sandbox Code Playgroud)

  • 如果 OnStartCommand 未触发,请尝试在 DataSource 类上方添加 [Service] (3认同)
  • 从Service继承必须在Android项目中完成,而不是在跨平台共享代码中完成。 (2认同)
  • 答案中有两处缺失:(1) 在 DataSource 类上方添加 [Service] (2) DataSource 类不会在共享代码中创建,而是在 Android 项目下创建。 (2认同)