Android 14 – ACCESS_FINE_LOCATION никогда не запрашивался и не предоставлялся

мой манифест.xml:

<?xml version = "1.0" encoding = "utf-8"?>
<manifest xmlns:android = "http://schemas.android.com/apk/res/android">

    <uses-feature android:name = "android.hardware.camera" />
    <uses-feature android:name = "android.hardware.camera.autofocus"/>
    <uses-feature android:name = "android.hardware.location.gps" />

    <uses-permission android:name = "android.permission.INTERNET" />
    <uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name = "android.permission.CAMERA" />
    <uses-permission android:name = "android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name = "android.permission.POST_NOTIFICATIONS" />
    <uses-permission android:name = "android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name = "android.permission.FOREGROUND_SERVICE_LOCATION" />
    <uses-permission android:name = "android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name = "android.permission.ACCESS_BACKGROUND_LOCATION" />
    <uses-permission android:name = "android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE" />

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

</manifest>

Тогда мой код для запроса разрешений в моей основной деятельности выглядит следующим образом:

 ActivityResultLauncher<String[]> permissionRequest =
        registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), result -> {
            boolean hasAllPermissions = true;
            for (Boolean value : result.values()) {
                hasAllPermissions = hasAllPermissions && value;
            }
            if (hasAllPermissions){
                startLocationService();
            }
            else {
                needsPermissionsDialog.show();
            }
        });

    private void checkPermissions() {
        permissionRequest.launch(new String[]{
                Manifest.permission.INTERNET,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.POST_NOTIFICATIONS,
                Manifest.permission.CAMERA,
                Manifest.permission.ACCESS_BACKGROUND_LOCATION,
                Manifest.permission.FOREGROUND_SERVICE,
                Manifest.permission.FOREGROUND_SERVICE_LOCATION
        });
    }
    private void startLocationService(){
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            if (locationService == null) {
                Intent locationServiceIntent = new Intent(MainActivity.this, LocationService.class);
                startForegroundService(locationServiceIntent);
                bindService(locationServiceIntent, locationServiceConnection, 0);
            }
        }
        else {
            Toast.makeText(this, "Missing location permission", Toast.LENGTH_SHORT).show();
        }
    }

Функция checkPermissions() вызывается после возврата с экрана входа в приложение (что представляет собой простой экран разблокировки с помощью пин-кода). Я также попробовал в качестве первого шага поместить вызов в методы onCreate() и onStart(), но ничего не изменилось. Поведение все время одинаковое. Никогда не удавалось предоставить разрешения FINE_LOCATION

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
      
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == LOGIN_ACTIVITY_REQUEST) {
            if (resultCode == RESULT_OK) {
                checkPermissions();
                ...

На старом андроиде работает на 100% без проблем, служба запускается, могу к ней привязаться и получать обновления местоположения. Однако на Android 14 ActivityResultContracts.RequestMultiplePermissions() результат имеет false для разрешения ACCESS_FINE_LOCATION. Когда я отключаю разрешение в настройках (Android) для приложения, оно запрашивает разрешение (см. изображение), но предоставляет его только для ACCESS_BACKGROUND_LOCATION, а результат ACCESS_FINE_LOCATION по-прежнему остается ложным.

Если я удалю ACCESS_BACKGROUND_LOCATION из манифеста, опция «Разрешение местоположения» в настройках (Android) приложения исчезнет. Если удалить его из списка permissionRequest.launch(), я не получу приглашения разрешить доступ к местоположению.

Также не имеет значения, добавлю ли я FINE на ACCESS_COARSE_LOCATION где угодно (список или манифест). В результате он также всегда становится ложным.

Все остальные диалоговые окна запроса разрешений работают нормально.

Проблема была воспроизведена на 2 устройствах Xiaomi и 1 Pixel, поэтому она даже не зависит от конкретного устройства.

P.S. Я знаю, что это мой третий вопрос в этой теме, но это также моя третья реализация, и до сих пор нет результата.

Можете ли вы опубликовать полный код, например, где вы вызываете функцию checkPermissions?

Bob 02.07.2024 11:28

Обновил пост со звонком.

LGstudio 02.07.2024 12:00

@LGstudio, вы нашли решение этой проблемы? Я столкнулся с той же проблемой. До Android14 все работало нормально

Gabrielle 18.07.2024 16:26
2
3
155
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Попробуйте реализовать так, как предлагает Google:

Первый запрос на разрешение местоположения COARSE и FINE, как только оно будет предоставлено, затем запрашивайте только ACCESS_BACKGROUND_LOCATION. Это возможно только при переходе к настройкам разрешений приложения.

public static void requestPermissions(Activity activity) {
    // Request foreground permissions first
    String[] foregroundPermissions = new String[]{
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_FINE_LOCATION
    };

    ActivityCompat.requestPermissions(activity, foregroundPermissions, REQUEST_FOREGROUND_PERMISSIONS);
}

private static final int REQUEST_FOREGROUND_PERMISSIONS = 1;

public static void onRequestPermissionsResult(Activity activity, int requestCode, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, requestCode, grantResults);
    if (requestCode == REQUEST_FOREGROUND_PERMISSIONS) {
        if (hasPermissions(activity, foregroundPermissions)) {
            // Permissions granted, check for Android version and request background permission if needed
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                String[] backgroundPermission = new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION};
                ActivityCompat.requestPermissions(activity, backgroundPermission, REQUEST_BACKGROUND_PERMISSION);
            } else {
                showBackgroundLocationControls(activity);
            }
        } else {
            Toast.makeText(activity, "Location permission denied", Toast.LENGTH_SHORT).show();
        }
    } else if (requestCode == REQUEST_BACKGROUND_PERMISSION) {
        if (hasPermissions(activity, new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION})) {
            // Implement your logic to show BackgroundLocationControls here
        } else {
            Toast.makeText(activity, "Background location permission denied", Toast.LENGTH_SHORT).show();
        }
    }
}

private static boolean hasPermissions(Activity activity, String[] permissions) {
    for (String permission : permissions) {
        if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
            return false;
        }
    }
    return true;
}

Пожалуйста, прочитайте этот пост полностью и попробуйте реализовать так же и эту ссылку.

Примечание. В магазине Google Play действует политика определения местоположения устройства, ограничивающая фоновый доступ к данным о местоположении приложениям, которым это необходимо для выполнения основных функций и которые соответствуют соответствующим требованиям политики.

ACCESS_BACKGROUND_LOCATION всплывающее окно:

В атрибуции от - https://www.paget96projects.com/guides/android-app-background-location-permission-and-play-store#google_vignette


Если вы все еще сталкиваетесь с какой-либо проблемой, обратитесь к этому пакету.

https://github.com/android/platform-samples/tree/main/samples/location/src/main/java/com/example/platform/location/permission

Спасибо за ваши решения, но это тоже не работает. При запросе разрешения на передний план он автоматически приводит к отказу, даже не спрашивая пользователя. Я убедился, что все разрешения в моем приложении отключены, удалив его, поэтому раньше не было предоставлено никаких разрешений на фоновое местоположение.

LGstudio 03.07.2024 08:04

@LGstudio используйте код этих классов и запустите его в своем приложении.

Bob 03.07.2024 08:16

но приложение mu — очень старое приложение, не требующее создания архитектуры. Как я вообще могу включить это в свой код?

LGstudio 03.07.2024 08:25

@LGstudio В своем ответе я поделился Java-версией того же кода, можете ли вы отладить и поделиться выводами журнала.

Bob 03.07.2024 08:28

ваша функция результата выглядит следующим образом: super.onRequestPermissionsResult(int requestCode, int requestCode, int[]grantResults); Но в AppCompatActivity нет такого суперметода. Существует только публичный void onRequestPermissionsResult(int requestCode, String[] Permissions, int[]grantResults). Я создал чистое действие в своем приложении. Только ваш код вызывается в onStart() (и изменяется этот супервызов для получения результата), и я мгновенно получаю «Разрешение на определение местоположения отклонено». Никакого диалога с вопросом об этом.

LGstudio 03.07.2024 09:11

@LGstudio не звоните onStart() также можете ли вы поделиться обновленным кодом здесь, на Pastie.org

Bob 03.07.2024 09:23

Я создал совершенно новое чистое приложение с одним действием: запросом местоположения на основе вашего кода. Это работает на 100%. без проблем. Скопируйте и вставьте его в мое приложение. В качестве нового чистого действия или в уже существующем вызов его в onStart() или onCreate() не имеет значения, он просто возвращает PERMISSION_DENIED для запроса местоположения на переднем плане, не открывая диалогового окна пользователю.

LGstudio 03.07.2024 09:27

Другие вопросы по теме