Visual Studio Xamarin表单,移动的锁定时前台服务不工作

dly7yett  于 2022-12-14  发布在  其他
关注(0)|答案(1)|浏览(121)

我正在创建一个每10分钟向服务器发送用户位置信息的应用程序。为了即使在应用程序处于后台或移动的被锁定时也能正常工作,我使用了前台服务。当应用程序直接从Visual Studio构建到模拟器或通过USB构建到真实的设备时,即使在设备锁定时,一切都能正常工作。**当设备断开连接或执行发布构建时-设备锁定时,前台服务不会发送信息。**有人有过此方面的经验吗?谢谢

共享代码:

  • 主页面.xaml.cs:*
if (MainViewModel.WorkingActions.Contains(buttonText))
{
     DependencyService.Get<IBackgroundService>().StartService(1);

     MessagingCenter.Subscribe<Application>(this, "Ping", async (sender) =>
     {
         await PingWorkingToServer();
     });
 }
 else
 {
     DependencyService.Get<IBackgroundService>().StopService();
 }
  • I背景服务.cs*
public interface IBackgroundService
{
    // 1 = logged in, 2 = not logged in
    void StartService(int pingType);
    void StopService();
}

安卓系统:

  • 安卓服务助手.cs*
internal class AndroidServiceHelper : IBackgroundService
{
    private static readonly Context context = global::Android.App.Application.Context;
    private static readonly Intent intent = new Intent(context, typeof(DependentService));
    private bool isRunning = false;
    // 1 = logged in 2 = not logged in
    public void StartService(int pingType)
    {
        intent.PutExtra("PingType", pingType);
        if(!isRunning)
        {
            if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
            {
                context.StartForegroundService(intent);
            }
            else
            {
                context.StartService(intent);
            }
            isRunning = true;
        }
    }

    public void StopService()
    {
        context.StopService(intent);
        isRunning = false;
    }
}
  • 受抚养者服务.cs*
[Service(Enabled = true)]
public class DependentService : Service
{
    private Handler handler;
    private Action runnable;
    private bool isStarted;
    private int DELAY_BETWEEN_MESSAGES;
    private readonly int NOTIFICATION_SERVICE_ID = 1001;
    private readonly int NOTIFICATION_PING_ID = 1002;
    private readonly string NOTIFICATION_CHANNEL_ID = "1003";
    private readonly string NOTIFICATION_CHANNEL_NAME = "MyChannel";
    private const int ONE_MINUTE_MILIS = 60000;
    private int PingType = -1;

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

        var minutes = Xamarin.Essentials.Preferences.Get("PingTime", 10);

        DELAY_BETWEEN_MESSAGES = minutes * ONE_MINUTE_MILIS;

        handler = new Handler();

        runnable = new Action(() =>
        {
            if (isStarted)
            {
                DispatchNotificationThatPingIsGenerated();
                handler.PostDelayed(runnable, DELAY_BETWEEN_MESSAGES);
            }
        });
    }

    private void DispatchNotificationThatPingIsGenerated()
    {
        var intent = new Intent(this, typeof(MainActivity));
        intent.AddFlags(ActivityFlags.ClearTop);

        Notification.Builder notificationBuilder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
            .SetSmallIcon(Resource.Drawable.dochazka_icon)
            .SetContentTitle("Ukládání pozice")
            .SetContentText("Právě odesílám vaši polohu.")
            .SetAutoCancel(true);

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

        if (PingType == 1)
        {
            MessagingCenter.Send(Xamarin.Forms.Application.Current, "Ping");
        }
        else if (PingType == 2)
        {
            MessagingCenter.Send(Xamarin.Forms.Application.Current, "PingLocally");
        }
    }

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

    public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        if (isStarted)
        {
            // service is already started
        }
        else
        {
            PingType = intent.GetIntExtra("PingType", -1);
            CreateNotificationChannel();
            DispatchNotificationThatServiceIsRunning();

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

    //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.dochazka_icon)
               .SetSound(null)
               .SetChannelId(NOTIFICATION_CHANNEL_ID)
               .SetPriority(NotificationCompat.PriorityDefault)
               .SetAutoCancel(false)
               .SetContentTitle("Ukládání pozice")
               .SetContentText("Jste v práci, aplikace pravidelně ukládá polohu.")
               .SetOngoing(true);

        StartForeground(NOTIFICATION_SERVICE_ID, builder.Build());
    }

    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);

        NotificationManager notificationManager = (NotificationManager)GetSystemService(NotificationService);
        notificationManager.CreateNotificationChannel(notificationChannel);
    }
}
  • 安卓清单.xml*
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
<application android:label="Docházka lokalita" android:theme="@style/MainTheme" android:icon="@mipmap/launcher_foreground">
    <service android:name=".DependentService" android:foregroundServiceType="location" />
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-feature android:name="android.hardware.location" android:required="false" />
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
<uses-feature android:name="android.hardware.location.network" android:required="false" />
<queries>
    <intent>
        <action android:name="android.support.customtabs.action.CustomTabsService" />
    </intent>
</queries>
eeq64g8w

eeq64g8w1#

您可以使用wakelock在屏幕关闭或锁定后保持cpu唤醒状态,以便服务继续运行。例如:

public Constructor()
{
    PowerManager powerManager = Android.App.Application.Context.GetSystemService(Context.PowerService) as PowerManager;
    _wakeLock = powerManager.NewWakeLock(WakeLockFlags.Partial, "ServiceWakeLock");
}

public override void OnCreate()
{
    base.OnCreate();
    if (_wakeLock != null)
        _wakeLock.Acquire();
}

public override void OnDestroy()
{
    if (_wakeLock != null)
    {
        _wakeLock.Release();
        _wakeLock = null;
    }
    ...
    base.OnDestroy();
}

相关问题