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

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

我使用下面的应用程序代码每 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

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

java android service notifications background
2个回答
9
投票

根据官方文档:

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

但是,在 Android 11(API 级别 30)及更高版本上,系统对话框 不包括“始终允许”选项。相反,用户必须 在设置页面启用后台定位,如图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);

有关更多信息,请参阅
请求后台位置


1
投票
AndroidManifest.xml

文件的服务标记中提及

android:foregroundServiceType="location"
示例:

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

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