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
{
...
}
我正在使用 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
{
...
}