Xamarin后台定位服务不断崩溃

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

我正在尝试制作一个xamarin应用程序,带有android和ios。 我已经制作了一项服务,以间隔时间广播用户位置,但每次尝试广播(使用 SendLocationToServer() )时,它都会使应用程序崩溃。

[Service]
    public class LocationService : Service {
        public string role = "";
        public string auth = "";
        System.Timers.Timer _timer;
        const string foregroundChannelId = "location_service_channel";
        const int serviceId = 209345;
        const string channelId = "location_service_channel"; 
        const string channelName = "Location Service";
        const string endpoint = @"REMOVED FOR STACK OVERFLOW POST"; 

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

        public override void OnCreate() {
            var notificationManager = (NotificationManager)GetSystemService(NotificationService);

            if (Build.VERSION.SdkInt >= BuildVersionCodes.O) {
                var channel = new NotificationChannel(channelId, channelName, NotificationImportance.Default) {
                    Description = "Location Service is running"
                };
                notificationManager.CreateNotificationChannel(channel);
            } 
        }

        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId) {
            StartForeground(serviceId, CreateNotification());

            auth = intent.GetStringExtra("authToken");
            role = intent.GetStringExtra("role");

            _timer = new System.Timers.Timer(10000); 

            _timer.Elapsed += async (sender, e) => {
                try {
                    await SendLocationToServer();
                } catch (Exception ex) {
                    // Log exception
                    Toast.MakeText(Android.App.Application.Context, "Timer Toast " + ex.Message, ToastLength.Short).Show();
                }
            };
            _timer.AutoReset = true;
            _timer.Start();

            return StartCommandResult.Sticky;
        }

        private Notification CreateNotification() {
            var intent = new Intent(MainActivity.Instance, typeof(MainActivity));
            intent.AddFlags(ActivityFlags.SingleTop);
            intent.PutExtra("Title", "Message");

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

            var notificationBuilder = new Notification.Builder(MainActivity.Instance)
                .SetContentTitle(channelName)
                .SetContentText("Broadcasting location in the background")
                .SetSmallIcon(Resource.Drawable.Icon_small)
                .SetOngoing(true)
                .SetContentIntent(pendingIntent);

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

                var notificationManager = MainActivity.Instance.GetSystemService(Context.NotificationService) as NotificationManager;
                if (notificationManager != null) {
                    notificationBuilder.SetChannelId(foregroundChannelId);
                    notificationManager.CreateNotificationChannel(notificationChannel);
                }
            }

            return notificationBuilder.Build(); 



            //try {
            //  var notification = new Notification.Builder(this, channelId)
            //  .SetContentTitle(channelName)
            //  .SetContentText("Broadcasting location in the background")
            //  .SetSmallIcon(Resource.Drawable.Icon_small)
            //  .SetOngoing(true) // Keep the notification active
            //  .Build();

            //  return notification;
            //}
            //catch(Exception e) {
            //  Toast.MakeText(Android.App.Application.Context, "Error: " + e.Message, ToastLength.Short).Show();
            //  return null; 
            //}                 
        }

        private async Task SendLocationToServer() {
            if (!string.IsNullOrEmpty(role) && !string.IsNullOrEmpty(auth)) {
                using (var client = new HttpClient()) {
                    try {
                        var location = await Geolocation.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.Best));

                        if (location != null) {
                            var gpsData = new {
                                AuthToken = auth,
                                Role = role,
                                Longitude = location.Longitude,
                                Latitude = location.Latitude
                            };

                            var jsonContent = JsonConvert.SerializeObject(gpsData);
                            var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");

                            var response = await client.PostAsync(endpoint + "/logbeacon", content);
                            //i++;
                            if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized) {
                                Toast.MakeText(Android.App.Application.Context, "Unauthorized. Please login again", ToastLength.Short).Show();
                            } else if (response.StatusCode == System.Net.HttpStatusCode.OK) {
                                Toast.MakeText(Android.App.Application.Context, "Check broadcast 3", ToastLength.Short).Show();
                            } else {
                                Toast.MakeText(Android.App.Application.Context, "Connection Error. ", ToastLength.Short).Show();
                            }
                        } else {
                        }
                    } catch (Exception ex) {
                        // Handle exception
                        Toast.MakeText(Android.App.Application.Context, "Check broadcast 4 " + ex.Message, ToastLength.Short).Show();
                        await client.GetAsync(endpoint + "/test/" + ex.Message); // TESTING 
                    }
                }
            }
        }

        public override void OnDestroy() {
            _timer?.Stop();
            _timer?.Dispose();
            base.OnDestroy();
        }
    }

实施者:

[assembly: Xamarin.Forms.Dependency(typeof(LocationServiceImplementation))]
namespace MyAppName.Droid
{
    public class LocationServiceImplementation : ILocationService {
        public void StartLocationService(string role, string auth) {
            Toast.MakeText(Android.App.Application.Context, "Starting", ToastLength.Short).Show();

            var intent = new Intent(MainActivity.Instance, typeof(LocationService));

            intent.PutExtra("auth", auth);
            intent.PutExtra("role", role);

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

        public void StopLocationService() {
            Toast.MakeText(Android.App.Application.Context, "Stopping", ToastLength.Short).Show();

            throw new NotImplementedException();
        }
    }

在Manifest和MainActivity中设置和请求权限:包括粗略位置、精细位置和始终位置。请求的顺序花了一些时间才弄清楚,但现在请求正确了。

这个函数在android项目的MainActivity中:

public async Task GetLocationConsent() {
            var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>();
            if (status == PermissionStatus.Denied || status == PermissionStatus.Unknown) {
                status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
            }

            // Only request background location on Android 10 (API level 29) or higher
            if (status == PermissionStatus.Granted && Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Q) {
                var backgroundStatus = await Permissions.CheckStatusAsync<Permissions.LocationAlways>();
                if (backgroundStatus == PermissionStatus.Denied || backgroundStatus == PermissionStatus.Unknown) {
                    await Permissions.RequestAsync<Permissions.LocationAlways>();

                    // Check again if permission is not granted, then navigate to settings
                    backgroundStatus = await Permissions.CheckStatusAsync<Permissions.LocationAlways>();
                    if (backgroundStatus != PermissionStatus.Granted) {
                        // Inform the user to manually enable background location in settings
                        Toast.MakeText(Application.Context, "Please enable Location Always in App Permissions.", ToastLength.Long).Show();

                        var intent = new Intent(Android.Provider.Settings.ActionApplicationDetailsSettings);
                        intent.AddFlags(ActivityFlags.NewTask);
                        var uri = Android.Net.Uri.FromParts("package", Application.Context.PackageName, null);
                        intent.SetData(uri);
                        Application.Context.StartActivity(intent);

                        // Show a message to guide the user
                        Toast.MakeText(Application.Context, "Please enable Background Location in App Permissions.", ToastLength.Long).Show();
                    }
                }
            }
        }

我花了很多时间试图破解这个难题,以至于我看不清,工作的截止日期很快就到了……任何帮助将不胜感激。请。

我正在尝试在 Android 上运行后台服务,定期广播用户位置,但当我尝试时应用程序崩溃了。

android xamarin location background-service foreground-service
1个回答
0
投票

显然问题是“异步”。一旦我改变了

var location = await Geolocation.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.Best));
进入这个
var location = await Task.Run(async () => await Geolocation.GetLocationAsync(new GeolocationRequest(GeolocationAccuracy.Best)));
并改变了
SendLocationToServer()
为了不再异步,代码运行顺利。我不知道为什么代码不喜欢运行异步,但是将该异步部分隔离到单个任务中,解决了崩溃。

© www.soinside.com 2019 - 2024. All rights reserved.