簡體   English   中英

當應用程序移至后台時,在前台服務中獲取位置更新不起作用

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

我正在使用以下應用程序代碼每 5 秒從 GPS 接收位置更新,並將 output 打印到日志中。 只要應用程序處於前台,這對我來說就很好,但是當它移動到后台時更新會停止,直到它被帶回前台。 我正在使用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);
        }       
    }
}

這是服務 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 中得到一個 output。 這是我正在尋找的行為。 當應用程序進入后台時會出現問題,然后我在 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

但是在這最后一條消息之后 - 在我將應用程序帶回前台之前不再進行更新。 我希望它一直保持運行 - 為此還需要做什么?

根據官方文檔:

當您的應用程序中的某個功能請求運行 Android 10(API 級別 29)的設備上的后台位置時,系統權限對話框包含一個名為“始終允許”的選項。 如果用戶選擇此選項,您應用中的功能將獲得后台位置訪問權限。

但是,在 Android 11(API 級別 30)及更高版本上,系統對話框不包括始終允許選項。 相反,用戶必須在設置頁面上啟用后台定位,如圖 3 所示。

因此,您需要在應用程序的“設置”頁面中始終看到名為“允許”的選項

在此處輸入圖像描述

為此,您必須在清單中擁有此權限:

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

如您所見,對話框始終顯示“允許”

在此處輸入圖像描述

但是在 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);
    }

最后,如果您選中Allow all time選項,您的應用程序將能夠在后台監聽位置變化

更新:

對於 Android 30 及更高版本,您可以通過直接使用以下代碼行打開位置權限頁面來要求用戶保證后台位置:

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

有關更多信息,請參閱請求后台位置

AndroidManifest.xml文件的服務標簽中提及android.foregroundServiceType="location"

例子:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM