具有xamarin形式的隔离过程的后台服务

问题描述 投票:0回答:1

你好朋友你好吗?我告诉你,我正在练习在后台运行服务。我想要实现的是,即使关闭了应用程序,该服务仍在运行。我遵循了说明以下内容的Microsoft文档:docs.microsoft.com/en-us/xamarin/android/app-fundamentals/services

Isolated Process –隔离进程是在自己的沙箱中运行的进程,与系统的其余部分隔离,并且没有自己的特殊权限。要在隔离的进程中运行服务,请将ServiceAttribute的IsolatedProcess属性设置为true,如以下代码片段所示:

示例代码:

[Service(Name = "com.xamarin.TimestampService",
     IsolatedProcess= true,
     Process="com.xamarin.xample.messengerservice.timestampservice_process",
     Exported=true)]

我已完成所有步骤,但该服务甚至无法运行。

我使用的代码如下:

MainActivity.cs

  public static Intent notificationServiceIntent;
    internal bool isStarting = false;
    // This is the package name of the APK, set in the Android manifest
    const string REMOTE_SERVICE_COMPONENT_NAME = "com.myapp";
    // This is the name of the service, according the value of ServiceAttribute.Name
    const string REMOTE_SERVICE_PACKAGE_NAME = "com.myapp.notificationservice_process";
    protected override void OnCreate(Bundle savedInstanceState)
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;
        base.OnCreate(savedInstanceState);

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

        LoadApplication(new App());
        CreateNotificationFromIntent(Intent);
        notificationServiceIntent = new Intent(this.BaseContext, typeof(PDANotificationService));
        ComponentName cn = new ComponentName(REMOTE_SERVICE_PACKAGE_NAME, REMOTE_SERVICE_COMPONENT_NAME);
        notificationServiceIntent.SetComponent(cn);
        StartService(notificationServiceIntent);
    }

NotificationService.cs

[Service(Name = "com.myapp.notificationservice", IsolatedProcess = true,
                 Process = "com.myapp.notificationservice_process", Exported = true, 
                 Label = "Isolated Process service that has trouble starting")]
public class NotificationService: Service
{
    System.Threading.Timer _timer;
    INotificationManager notificationManager;
    int notificationNumber;


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

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

    [return: GeneratedEnum]
    public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
    {
        if(notificationManager==null)
            notificationManager = DependencyService.Get<INotificationManager>();
        sendNotification();

        base.OnStartCommand(intent, flags, startId);
        return StartCommandResult.Sticky;

    }

    public void sendNotification()
    {
        Device.StartTimer(new TimeSpan(0, 1, 0), () =>
        {
            notificationNumber++;
            string title = $"Local Notification #{notificationNumber}";
            string message = $"You have now received {notificationNumber} notifications!";
            notificationManager.ScheduleNotification(title, message);
            return true;
        });

    }
}

BroadcastReceiver.cs

[BroadcastReceiver]
[IntentFilter(new[] { Intent.ActionBootCompleted })]
public class BroadcastReceiver : BroadcastReceiver
{
    // This is the package name of the APK, set in the Android manifest
    const string REMOTE_SERVICE_COMPONENT_NAME = "com.myapp";
    // This is the name of the service, according the value of ServiceAttribute.Name
    const string REMOTE_SERVICE_PACKAGE_NAME = "com.myapp.notificationservice_process";
    public override void OnReceive(Context context, Intent intent)
    {
        Log.Info("TestApp", "******* Loading Application *******");

        try
        {
            if (intent.Action.Equals(Intent.ActionBootCompleted))
            {
                Intent service = new Intent(context, typeof(PDANotificationService));
                ComponentName cn = new ComponentName(REMOTE_SERVICE_PACKAGE_NAME, REMOTE_SERVICE_COMPONENT_NAME);
                service.SetComponent(cn);
                service.AddFlags(ActivityFlags.NewTask);
                context.StartService(service);
            }
        }
        catch (Exception ex)
        {
            Log.Error("TestApp", "******* Error message *******: " + ex.Message);
        }
    }
}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.myapp" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
<application android:label="My app" android:icon="@mipmap/ic_launcher" />

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.PERSISTENT_ACTIVITY" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND" />
<uses-permission android:name="android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.STATUS_BAR" />

我能够在后台运行应用程序时运行该服务。但是现在,即使关闭主应用程序,我也需要保持服务运行。

我已经尝试解决了将近2个星期,但仍然找不到答案。如果您能帮助我,我真的非常感谢。

预先,非常感谢。

c# xamarin.forms xamarin.android
1个回答
0
投票

您可以在关闭应用程序时通过发出前通知来使用Foreground Sevice以保持活动状态。

这里是一个简单的示例,您可以参考并添加到您的项目中。

1。创建服务MyService.cs

[Service(Enabled = true)]
public class MyService : Service
{
    private Handler handler;
    private Action runnable;
    private bool isStarted;
    private int DELAY_BETWEEN_LOG_MESSAGES = 5000;
    private int NOTIFICATION_SERVICE_ID = 1001;
    private int NOTIFICATION_AlARM_ID = 1002;
    private string NOTIFICATION_CHANNEL_ID = "1003";
    private string NOTIFICATION_CHANNEL_NAME = "MyChannel";
    public override void OnCreate()
    {
        base.OnCreate();

        handler = new Handler();

        //here is what you want to do always, i just want to push a notification every 5 seconds here
        runnable = new Action(() =>
        {
           if (isStarted)
            {
                DispatchNotificationThatAlarmIsGenerated("I'm running");
                handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);
            }
        });
    }

    public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        if (isStarted)
        {
            // service is already started
        }
        else
        {
            CreateNotificationChannel();
            DispatchNotificationThatServiceIsRunning();

            handler.PostDelayed(runnable, DELAY_BETWEEN_LOG_MESSAGES);
            isStarted = true;
        }
        return StartCommandResult.Sticky;
    }

    public override void OnTaskRemoved(Intent rootIntent)
    {
        //base.OnTaskRemoved(rootIntent);
    }

    public override IBinder OnBind(Intent intent)
    {
        // Return null because this is a pure started service. A hybrid service would return a binder that would
        // allow access to the GetFormattedStamp() method.
        return null;
    }

    public override void OnDestroy()
    {
        // Stop the handler.
        handler.RemoveCallbacks(runnable);

        // Remove the notification from the status bar.
        var notificationManager = (NotificationManager)GetSystemService(NotificationService);
        notificationManager.Cancel(NOTIFICATION_SERVICE_ID);

        isStarted = false;
        base.OnDestroy();
    }

    private void CreateNotificationChannel()
    {
        //Notification Channel
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_NAME, NotificationImportance.Max);
        notificationChannel.EnableLights(true);
        notificationChannel.EnableVibration(true);
        notificationChannel.SetVibrationPattern(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 });


        NotificationManager notificationManager = (NotificationManager)this.GetSystemService(Context.NotificationService);
        notificationManager.CreateNotificationChannel(notificationChannel);
    }

    //start a foreground notification to keep alive 
    private void DispatchNotificationThatServiceIsRunning()
    {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
               .SetDefaults((int)NotificationDefaults.All)
               .SetSmallIcon(Resource.Drawable.Icon)
               .SetVibrate(new long[] { 100, 200, 300, 400, 500, 400, 300, 200, 400 })
               .SetSound(null)
               .SetChannelId(NOTIFICATION_CHANNEL_ID)
               .SetPriority(NotificationCompat.PriorityDefault)
               .SetAutoCancel(false)
               .SetContentTitle("Mobile")
               .SetContentText("My service started")
               .SetOngoing(true);

        NotificationManagerCompat notificationManager = NotificationManagerCompat.From(this);
        StartForeground(NOTIFICATION_SERVICE_ID, builder.Build());
    }

    //every 5 seconds push a notificaition
    private void DispatchNotificationThatAlarmIsGenerated(string message)
    {
        var intent = new Intent(this, typeof(MainActivity));
        intent.AddFlags(ActivityFlags.ClearTop);
        var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);

        Notification.Builder notificationBuilder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
            .SetSmallIcon(Resource.Drawable.Icon)
            .SetContentTitle("Alarm")
            .SetContentText(message)
            .SetAutoCancel(true)
            .SetContentIntent(pendingIntent);

        var notificationManager = (NotificationManager)GetSystemService(NotificationService);
        notificationManager.Notify(NOTIFICATION_AlARM_ID, notificationBuilder.Build());
    }
}

2。您的活动:

protected override void OnResume()
  {
      base.OnResume();
      StartMyRequestService();
  }
public void StartMyRequestService()
  {
      var serviceToStart = new Intent(this, typeof(MyService));
      StartService(serviceToStart);
  }
© www.soinside.com 2019 - 2024. All rights reserved.