Xamarin Forms 使用 CrossGeolocator 获取前台服务位置更新

Xamarin Forms Getting foreground service location updates with CrossGeolocator

我正在使用 CrossGeolocator 插件订阅 Xamarin Forms 应用程序中的位置更新,对于 Android(对于 iOS,即使应用程序在后台,位置更新也会继续)。

我实现了前台服务,这样即使应用程序进入后台,我也可以继续获取位置信息。

据我了解,如果我在前台服务中收听它们,我应该能够获得位置更新。

但是,当应用程序进入后台时,我没有得到位置更新。

我的服务数据源的 StartCommand:

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

    CrossGeolocator.Current.StartListeningAsync(TimeSpan.FromSeconds(10), 0, true, new Plugin.Geolocator.Abstractions.ListenerSettings
    {
        ActivityType = ActivityType.Other,
        PauseLocationUpdatesAutomatically = false,
        AllowBackgroundUpdates = true,
        DeferLocationUpdates = false,
        ListenForSignificantChanges = false,
    });

    CrossGeolocator.Current.PositionChanged += PositionChanged;
    CrossGeolocator.Current.PositionError += PositionError;


    return StartCommandResult.Sticky;
}

和事件:

private void PositionError(object sender, PositionErrorEventArgs e)
{
    Console.WriteLine($"{e.Error}");
}

private void PositionChanged(object sender, PositionEventArgs e)
{
    Console.WriteLine($"{e.Position.Latitude}, {e.Position.Longitude}");
}

事件仅在应用处于活动状态时触发。服务启动,设备显示服务为 运行.

的通知徽章

我已经分配了所需的权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.LOCATION_HARDWARE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

任何人都可以阐明实施情况吗? 如果需要,我可以提供额外的代码。

后台更新在每个平台上的处理方式略有不同。对于 Android,您需要集成订阅位置变化和用户界面绑定的前台服务。

您可以为此使用 Xamarin.Essentials 和 MessagingCenter。

  [Service]
 public class AndroidLocationService : Service
 {
    CancellationTokenSource _cts;
    public const int SERVICE_RUNNING_NOTIFICATION_ID = 10000;

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

    public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        _cts = new CancellationTokenSource();

        Notification notif = DependencyService.Get<INotification>().ReturnNotif();
        StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notif);

        Task.Run(() => {
            try
            {
                var locShared = new Location();
                locShared.Run(_cts.Token).Wait();
            }
            catch (OperationCanceledException)
            {
            }
            finally
            {
                if (_cts.IsCancellationRequested)
                {
                    var message = new StopServiceMessage();
                    Device.BeginInvokeOnMainThread(
                        () => MessagingCenter.Send(message, "ServiceStopped")
                    );
                }
            }
        }, _cts.Token);

        return StartCommandResult.Sticky;
    }

    public override void OnDestroy()
    {
        if (_cts != null)
        {
            _cts.Token.ThrowIfCancellationRequested();
            _cts.Cancel();
        }
        base.OnDestroy();
    }
}
}

有关详细信息,请查看下面 link 中的代码示例。

我通过添加以下内容找到了解决方案:

ForegroundServiceType = ForegroundService.TypeDataSync | ForegroundService.TypeLocation

作为前台服务中的服务属性

[Service(ForegroundServiceType = ForegroundService.TypeDataSync | ForegroundService.TypeLocation)]
public class LocationForegroundService : Service
{
    ...
}