当应用程序移到后台时,在前台服务中获取位置更新不起作用

Posted

技术标签:

【中文标题】当应用程序移到后台时,在前台服务中获取位置更新不起作用【英文标题】:getting location updates in foreground service isn't working when app is moved to background 【发布时间】:2021-07-06 10:14:20 【问题描述】:

我正在使用以下应用程序代码每 5 秒从 GPS 接收位置更新,并将输出打印到日志中。只要应用程序在前台,这对我来说就很好,但是当它移动到后台时更新会停止,直到它被带回前台。我正在使用galaxy s20(android 10)运行和调试,并且应用程序设置为永不休眠(android设置)。这是完整的过程描述:

我在清单上有这些权限:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.android.hardware.location.gps"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

这是启用 GPS 并创建服务的主要活动:

public class MainActivity extends AppCompatActivity 

    private LocationManager _locManager;
    private Intent _scanServiceIntent;

    public void onStart()
    
        super.onStart();
        boolean gps_enabled = _locManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        if (gps_enabled)
        
            ActivityCompat.requestPermissions(this, new String[]Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.INTERNET, 1);
            _scanServiceIntent = new Intent(this, ScanService.class);
            startService(_scanServiceIntent);
               
    

这是服务类 - 我正在创建一个通知以使服务始终运行 - 即使应用程序进入后台:

public class ScanService extends Service 

    private LocationListener _locListener;
    private LocationManager _locManager;


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
        super.onStartCommand(intent, flags, startId);
        String NOTIFICATION_CHANNEL_ID = "com.tandenkore.mychannel";

        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,0);

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
        Notification notification = notificationBuilder.setOngoing(true)
                .setContentTitle("App is running in background")
                .setPriority(NotificationManager.IMPORTANCE_MAX)
                .setCategory(Notification.CATEGORY_SERVICE)
                .setContentIntent(pendingIntent)
                .build();
        startForeground(300, notification);
        return START_STICKY;
    

    @Override
    public void onCreate() 
        _locListener = new MyLocationListener();
        _locManager = (LocationManager)getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        _locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, _locListener);
    

    @Override
    public void onDestroy() 
        super.onDestroy();
        stopForeground(true);
        _locManager.removeUpdates(_locListener);
    

    class MyLocationListener implements LocationListener 
        @Override
        public void onLocationChanged(Location location)
        
            Log.v(TAG, "location changes");
        
    

当我在设备上调试它并且应用程序在前台时,我每 5 秒在 logcat 中得到一个“位置更改”行的输出。这是我正在寻找的行为。 当应用程序进入后台时会出现问题,然后我在 logcat 中收到以下内容:

2021-04-11 00:00:26.648 26160-26160/com.tandenkore.application V/application: location changes
2021-04-11 00:00:31.657 26160-26160/com.tandenkore.application V/application: location changes
2021-04-11 00:00:36.656 26160-26160/com.tandenkore.application V/application: location changes
2021-04-11 00:00:41.656 26160-26160/com.tandenkore.application V/application: location changes
2021-04-11 00:00:46.653 26160-26160/com.tandenkore.application V/application: location changes
2021-04-11 00:00:50.170 7241-7307/? E/RequestManager_FLP: [LocationManager] Paused by AppOps 7e14624(Listener) gps interval=5000 from com.tandenkore.application (10367)
2021-04-11 00:00:50.173 7241-7307/? I/RequestManager_FLP: onOpChanged, op=0 / packageName=com.tandenkore.application
2021-04-11 00:00:50.174 7241-7307/? I/PackageInfoManager_FLP: checkLocationAccess for com.tandenkore.application[gps,5000,100], result is false

但是在这最后一条消息之后 - 在我将应用程序带回前台之前不再进行更新。我希望它始终保持运行 - 为此还需要做什么?

【问题讨论】:

您是否尝试在清单中添加&lt;uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/&gt; 刚刚添加并测试了它 - 相同的行为...... 【参考方案1】:

根据官方文档:

当您应用中的某个功能请求设备上的后台位置时 运行 Android 10(API 级别 29)的系统权限对话框 包括一个名为“始终允许”的选项。如果用户选择这个 选项,您应用中的功能将获得后台位置访问权限。

但是,在 Android 11(API 级别 30)及更高版本上,系统对话框 不包括“始终允许”选项。相反,用户必须 在设置页面上启用背景定位,如图 3 所示。

所以你需要在你的应用程序的设置页面中看到这个名为Allow all time的选项

为此,您必须在清单中拥有此权限:

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

在 API 30 及以下设备上,以便 始终允许 选项在对话框中可见,当您要求用户授予他们权限时,您必须添加 "Manifest.permission.ACCESS_BACKGROUND_LOCATION"。如下

ActivityCompat.requestPermissions(MainActivity.this,
                new String[]Manifest.permission.ACCESS_BACKGROUND_LOCATION ,Manifest.permission.ACCESS_COARSE_LOCATION,Manifest.permission.ACCESS_FINE_LOCATION,
                1);

如您所见,对话框中有 Allow all the time

但在 Android Api 30 及更高版本上,您必须邀请用户根据 API手动检查此选项

所以如果你想加载设置页面你可以使用这个方法:

   // load the permission setting screen
    private void loadPermissionPage(Activity context) 
        Intent intent = new Intent();
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", context.getPackageName(), null);
        intent.setData(uri);
        context.startActivityForResult(intent, 0);
    

最后,如果您选中始终允许选项,您的应用程序将能够在后台监听位置变化

更新:

对于 Android 30 及更高版本,您可以通过直接使用以下代码行打开位置权限页面来要求用户保证后台位置:

requestPermissions(new String[]Manifest.permission.ACCESS_BACKGROUND_LOCATION, REQUEST_CODE);

欲了解更多信息,请参阅Request background location

【讨论】:

哇,伙计......很好的答案 - 将检查并更新 - 非常感谢 仍然没有时间测试 - 这周会做,当然会更新 - 谢谢帮助:) 如果这对你有帮助,请告诉我好运 Shay - 完美运行 - 非常感谢您提供的信息丰富的解释!【参考方案2】:

AndroidManifest.xml 文件的服务标签中提及android.foregroundServiceType="location"

例子:

<service
   android:name=".LocationServicePackage.LocationService"
   android:foregroundServiceType="location"
   android:enabled="true"
   android:exported="true" />

【讨论】:

以上是关于当应用程序移到后台时,在前台服务中获取位置更新不起作用的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序从后台返回到前台时,CMDeviceMotion 停止更新

将应用程序带到前台时获取准确的坐标

如何在应用程序处于后台时保持GPS接收器位置更新(Google Play服务位置API)

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

当应用程序处于后台/挂起状态时,CLLocation 不断更新

Xamarin Forms - 每 10 秒获取一次设备位置(当应用程序在前台/后台运行时)