当应用程序移至后台时,无法在前台服务中获取位置更新

getting location updates in foreground service isn't working when app is moved to background

我正在使用以下应用程序代码每 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 和创建服务的主要 activity:

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

这是服务 class - 我正在创建一个通知,以便一直提供服务 运行 - 即使应用程序进入后台:

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

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

根据官方文档:

When a feature in your app requests background location on a device that runs Android 10 (API level 29), the system permissions dialog includes an option named Allow all the time. If the user selects this option, the feature in your app gains background location access.

On Android 11 (API level 30) and higher, however, the system dialog doesn't include the Allow all the time option. Instead, users must enable background location on a settings page, as shown in figure 3.

因此您需要在应用程序的设置页面中看到名为始终允许的选项

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

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

在 API 30 台及以下设备上,以便 Allow All the time 选项将在对话框中可见,您必须添加 "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);

如您所见,对话框有始终允许

但在 Android Api 30 及更高版本上,您必须邀请用户针对 API < 30 手动 选中此选项

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

   // 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

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

示例:

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

在这里试试表格 https://github.com/android/location-samples/tree/master/LocationUpdatesBackgroundKotlin 另请阅读限制 https://medium.com/@adrian.kajda/restrictions-to-background-location-and-foreground-services-in-android-11-9501adcd5795