首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >“允许所有时间”位置提示不会出现在Android 29中。

“允许所有时间”位置提示不会出现在Android 29中。
EN

Stack Overflow用户
提问于 2020-05-20 09:12:46
回答 7查看 34.3K关注 0票数 21

在SDK 29中,我无法获得“允许所有时间”的位置提示。我已经在清单中设置了这些权限:

代码语言:javascript
代码运行次数:0
运行
复制
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

并请求用户在运行时允许这些权限。但是它只返回“当应用程序打开时”和“拒绝”选项。

任何关于如何在SDK 29中显示它的想法。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2020-05-20 09:41:23

为了访问运行Android 10 (API级别29)或更高版本的设备的后台位置,还需要在清单文件中使用下面的权限。

代码语言:javascript
代码运行次数:0
运行
复制
 <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

有关更多信息,请参考下面的链接

https://developer.android.com/training/location/permissions?hl=fr

票数 17
EN

Stack Overflow用户

发布于 2020-05-20 09:30:59

在清单中添加权限ACCESS_BACKGROUND_LOCATION。要求在android 10及更高版本上显示始终允许选项。

参见https://developer.android.com/training/location/background#evaluate中的第二点

票数 7
EN

Stack Overflow用户

发布于 2020-06-28 16:00:53

我发现仅仅在清单中添加权限是不够的。我必须为用户提供一个选项,以便在启动时授予它,就像我需要为ACCESS_FINE_LOCATION所做的那样。有趣的是,当我检查这个应用程序中是否已经授予了后台权限时,它从来没有给出错误。但是如果我不检查,我就得不到“允许所有时间”的选项。这是在Android像素2版本10上。

这在安卓的10+版本中是唯一必要的。请求这两种权限使用户可以在对话框中选择.当然,用户可能不会选择“所有时间”。没有人能做这件事!

我有点不好意思添加我的代码,因为我知道这很糟糕。当然还有其他人可以改进它。我无法找到避免两次遍历权限的方法。

代码语言:javascript
代码运行次数:0
运行
复制
/**
 * This method lists all the permissions needed and gives reasons for each of them in a single
 * dialog. When the user presses ok, Android will popup separate dialogs for each permission
 * that is needed. In the case of location, the "Allow all the time" gives background permission
 * "Allow only while the app is running gives just the location permission while in foreground.
 * @return false if permissions are to be requested, true if they have already been granted.
 *
 * In Android 11 Build 30 things are a lot different. One has to ask for location first, approve
 * the 'while the app is running' option and then upon return in the Activity result, ask for
 * the background. Thus the new variable 'secondPassR' to handle this case. After the background
 * one comes back to the Activity result and then one can go into the main activity.
 */
static boolean secondPassR = false;
private static final int REQUEST_CODE_MULTIPLE_PERMISSIONS = 57;
private boolean requestPermissions(Activity activity)
{
    Log.v(TAG, "requestPermissions() called");
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
    {
        final List<String> permissionsList = new ArrayList<>();
        final List<String> reasonList = new ArrayList<>();

        if(!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION, activity))
        {
            reasonList.add("LOCATION PERMISSION: Needs needs to be granted for the Bluetooth " +
                    " LE scanner to discover devices!\n\n");
        }
        if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) && (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) || secondPassR)
        {
            if (!addPermission(permissionsList, Manifest.permission.ACCESS_BACKGROUND_LOCATION, activity))
            {
                reasonList.add("BACKGROUND PERMISSION: Needs to be granted for the Bluetooth " +
                        "LE Scanner to run in the background.\n\n");
            }
        }
        if (permissionsList.size() > 0)
        {
            if (reasonList.size() > 0)
            {
                // Need Rationale
                StringBuilder message = new StringBuilder(reasonList.get(0));
                for (int i = 1; i < reasonList.size(); i++)
                {
                    message.append(" ").append(reasonList.get(i));
                }
                final androidx.appcompat.app.AlertDialog.Builder builder =
                        new androidx.appcompat.app.AlertDialog.Builder(new ContextThemeWrapper(activity, R.style.Theme_AppCompat_Light));
                builder.setTitle("Demo needs the following permissions:");
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
                {
                    builder.setMessage(Html.fromHtml(message.toString(), Html.FROM_HTML_MODE_LEGACY));
                }
                else
                {
                    builder.setMessage(Html.fromHtml(message.toString()));
                }
                builder.setPositiveButton(android.R.string.ok, null);
                builder.setOnDismissListener(dialog -> {
                    Log.v(TAG, "Requesting permissions");
                    activity.requestPermissions(permissionsList.toArray(new String[0]),  // newer Java recommended
                            REQUEST_CODE_MULTIPLE_PERMISSIONS);
                });
                builder.show();
                return false;
            }
            activity.requestPermissions(permissionsList.toArray(new String[0]),   // newer Java recommended
                    REQUEST_CODE_MULTIPLE_PERMISSIONS);
        }
        else
        {
            return true;
        }
    }
    else
    {
        return true;
    }
    return false;
}

@TargetApi(23)
private boolean addPermission(List<String> permissionsList, String permission, Activity activity)
{
    Log.v(TAG,
            "addPermission() called with: " + "permissionsList = " +
                    "[" + permissionsList + "], permission = [" + permission + "]");
    if (ActivityCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED)
    {
        permissionsList.add(permission);
        // Check for Rationale Option
        return activity.shouldShowRequestPermissionRationale(permission);
    }
    return true;
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
{
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    String permission = "";
    Log.v(TAG,
            "onRequestPermissionsResult() called with: " + "requestCode = [" + requestCode +
                    "], permissions = [" + Arrays.toString(permissions) + "]," +
                    " grantResults = [" + Arrays.toString(grantResults) + "]");
    if (requestCode == REQUEST_CODE_MULTIPLE_PERMISSIONS)
    {
        for (int i = 0; i < permissions.length; i++)
        {
            switch (permissions[i])
            {
                case Manifest.permission.ACCESS_FINE_LOCATION:
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED)
                    {
                        Log.d(TAG, "H@H: onRequestPermissionsResult: FINE LOCATION PERMISSION");
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
                        {
                            Log.d(TAG, "H@H: Now requesting BACKGROUND PERMISSION for version 11+");
                            secondPassR = true;
                            requestPermissions(thisActivity);
                            return;
                        }
                    }
                    break;
                case Manifest.permission.ACCESS_BACKGROUND_LOCATION:
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED)
                    {
                        Log.d(TAG, "H@H: onRequestPermissionsResult: BACKGROUND PERMISSION");
                    }
                    break;
            }
        }
    }
    Log.d(TAG, "Starting primary activity");
    secondPassR = false;
    startActivityForResult(new Intent(context, PchaDemoPhg_Activity.class), EXIT_QUIT);
}

private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener)
{
    new AlertDialog.Builder(this)
            .setMessage(message)
            .setCancelable(false)
            .setPositiveButton("OK", okListener)
            .create()
            .show();
}

==============更新ANDROID 12和ActivityResultLauncher =======

有了Android 12,就会出现一组新的权限,我们不必再要求使用BTLE扫描仪的位置权限。THey还有一种处理活动结果的新方法,即ActivityResultLauncher,内置特性之一是运行时权限。下面是我现在用于从ANdroid 6+请求蓝牙扫描仪和后台权限的内容。我使用单权限启动程序在每个请求之前放置一个解释对话框。用户体验比我以前要好得多。(我包括字符串资源。)

代码语言:javascript
代码运行次数:0
运行
复制
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.util.Log;

import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.core.app.ActivityCompat;

import java.util.ArrayList;
import java.util.List;


/*
    resource strings used:
    <string name="permissions_connect_12">&lt;p&gt;This app needs permission to connect to Bluetooth devices&lt;/p&gt; </string>
    <string name="permissions_scan_12">&lt;p&gt;To search for Bluetooth devices this app needs permission to use the BLE scanner.&lt;/p&gt; </string>
    <string name="permissions_overlay_11">READ CAREFULLY! Setting permissions in Android 11+ is much more complicated!\n\n
        This app wants to popup a dialog when it discovers a PHD that it can work with.\n\n
        It needs Window-Overlay permissions to do that. Android will start a Settings system activity where it will list all the installed applications.\n\n
        You will need to scroll down to Health@Home PHG and tap it. That will bring you to the original pre-11 Settings system overlay permission activity.
        Give the permission and use the back arrow to exit. You will need use the back arrow once more to return to Health@Home.</string>
    <string name="permissions_location">&lt;p&gt;&lt;font color=\"#007700\"&gt;&lt;b&gt;LOCATION PERMISSION:&lt;/b&gt;&lt;/font&gt; Needs to be granted in order for this app to use the Bluetooth LE scanner.
        The scanner is needed to discover BLE health devices and know what they are.&lt;/p&gt;
        &lt;p&gt;&lt;font color=\"red\"&gt;&lt;b&gt;This app does NOT use location information or expose location information!&lt;/b&gt;&lt;/font&gt;
        Without this permission you will only be able to work with SPP and HDP devices.&lt;/p&gt;</string>
    <string name="permissions_background">&lt;p&gt;BACKGROUND PERMISSION: Needs to be granted for the Bluetooth LE Scanner to run in the background
        to support re-connection without user intervention.&lt;/p&gt;
        &lt;p&gt;Please select \'Allow all the time\'.&lt;/p&gt;</string>
 */
public class PermissionsActivity extends AppCompatActivity
{
    private final static String TAG = PermissionsActivity.class.getName();

    private final static boolean isVersionS_Plus = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S); // 31
    private final static boolean isVersionM_Plus = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M); // 23 (Marshmallow)
    private final static boolean isVersionN_Plus = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N);
    private static final boolean isVersionO_Plus = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O);
    private static final boolean isVersionR = (Build.VERSION.SDK_INT == Build.VERSION_CODES.R); // 30
    private static final boolean isVersionR_Plus = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R); // 30
    private static final boolean isVersionOtoR = ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)  // 26
            && (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R));  // 30


    private final List<String> permissionsList = new ArrayList<>();
    private final List<String> reasonList = new ArrayList<>();
    private int index = 0;  // Keeps track of what permission is being requested
    private int indexMax;   // The maximum number of permissions being asked for (set below)

    ActivityResultLauncher<String> activityResultLauncher =
            registerForActivityResult(new ActivityResultContracts.RequestPermission(), new ActivityResultCallback<Boolean>()
            {
                @Override
                public void onActivityResult(Boolean result)
                {
                    Log.d(TAG, "HH2: Permission " + permissionsList.get(index) + (result ? " granted" : "rejected"));
                    index++;
                    if (index >= indexMax)
                    {
                        handlePermissionSummary();
                    }
                    else
                    {
                        requestPermissions(index);
                    }
                }
            });

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        // too lazy to make a layout; your activity very likely has one!
        if (handlePermissions())
        {
            //setLoginScreen();  // Do what needs to be done after permissions are granted or if they already are granted
        }
    }

    // Method checks to see if the needed permissions are granted and if they are it returns true.
    // If they are not granted the method returns false but starts the process of asking the user to grant the permissions
    @SuppressLint("NewApi")
    private boolean handlePermissions()
    {
        if (isVersionS_Plus)  // Android 12 + (31+)  Completely new runtime permissions for Bluetooth in Android 12
        {                     // At least one no longer has to ask for location permissions for Bluetooth completely
                              // confusing the user.
            // Requesting BLUETOOTH_CONNECT, BLUETOOTH_SCAN, and ACCESS_BACKGROUND_LOCATION. The latter is still needed
            // to use the BTLE scanner in the background.

            // There is a weird bug in Android 12 with respect to the BLUETOOTH_CONNECT and BLUETOOTH_SCAN
            // permissions. If you need both, regardless of what order you ask for them in, you get only one
            // dialog from Android where the user grants the permission. But you have to ask for both permissions
            // (if you need both). See this bug: https://issuetracker.google.com/issues/214434187
            // Thus I skip the application dialog by making it empty for the second permission and just request
            // the permission. That way both permissions get granted.
            if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED)
            {
                permissionsList.add(Manifest.permission.BLUETOOTH_CONNECT);
                reasonList.add(getString(R.string.permissions_connect_12));
            }
            if (checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED)
            {
                permissionsList.add(Manifest.permission.BLUETOOTH_SCAN);
                reasonList.add(""); // Work-a-round. If empty, present no dialog explaining the request to the user
                //reasonList.add(getString(R.string.permissions_scan_12));
            }
            if (checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED)
            {
                permissionsList.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
                reasonList.add(getString(R.string.permissions_background));
            }
            indexMax = 3; // Need three permissions
        }
        else if (isVersionM_Plus)
        {
            // Need location permissions to use the BTLE Scanner. Some versions of Android after 6 require FINE location and
            // some require only coarse and some both. TO minimize headache, I always ask for FINE and place COARSE location
            // in the Manifest file. That gives you use of the BTLE scanner for all pre-12 versions of Android
            if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) // Android 6 +
            {
                permissionsList.add(Manifest.permission.ACCESS_FINE_LOCATION); // Require ACCESS_COARSE_LOCATION in Manifest file as well
                reasonList.add(getString(R.string.permissions_location));
                indexMax = 1;  // Need only one here
            }
            if (isVersionOtoR)  // Android 8 - 11. For these versions need BACKGROUND permission to use the scanner in the background.
            {
                if (checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED)
                {
                    permissionsList.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
                    reasonList.add(getString(R.string.permissions_background));
                    indexMax = 2;  // Need two permissions here
                }
            }
        }
        // If no permissions are needed, return true.
        if (permissionsList.size() == 0)
        {
            return true;
        }
        // Otherwise, begin the permission request sequence which involves launching permission requests.
        // The process is asynchronous, so the launch returns immediately.
        requestPermissions(index);
        return false;  // returning false indicates that permissions have not been granted and the request process is ongoing
    }

    // THis method pops up an application dialog explaining to the user why the application needs the requested permission.
    // When the user clicks OK, the permission request is launched. Android pops up whatever system action it dreams up to
    // handle the request. Sometimes it is a dialog, and sometimes it is an activity.
    // After the user responds, the result is returned in ActivityResultCallback above. The result is a boolean - true if
    // granted, false if not. Within the callback, the 'index' is checked. If there are more permissions to request,
    // this method is called again. If not, the summary method below is called.
    // It's ugly, but it is the only way I have been able to figure out how to place an explanation dialog before each
    // Android System action for the permission. Using the multiple permission approach I could not get my dialogs to
    // appear before each of the Android actions.
    @SuppressLint("NewApi")
    private void requestPermissions(int index)
    {
        if (reasonList.get(index).isEmpty()) // Work-a-round for Android 12. If explanation is empty then
        {
            // Skip explanation dialog but still request permission. Android pops up no dialog but auto-grants permission.
            activityResultLauncher.launch(permissionsList.get(index));
            return;
        }
        // Popup a dialog explaining why the app needs this permission and perhaps what Android is going to put you
        // through to grant the permission. For example, for BLUETOOTH_CONNECT/SCAN permissions Android pops up a
        // dialog. But for BACKGROUND permissions, Android presents an Activity. Exiting the dialog requires different
        // behavior from the user than exiting an activity.
        final androidx.appcompat.app.AlertDialog.Builder builder =
                new androidx.appcompat.app.AlertDialog.Builder(new ContextThemeWrapper(this, R.style.Theme_AppCompat_Light));
        builder.setTitle("Health@Home needs the following permission:");
        if (isVersionN_Plus)
        {
            builder.setMessage(Html.fromHtml(reasonList.get(index), Html.FROM_HTML_MODE_LEGACY));
        }
        else
        {
            builder.setMessage(Html.fromHtml(reasonList.get(index)));
        }
        builder.setPositiveButton(android.R.string.ok, null);
        builder.setOnDismissListener(dialog ->
        {
            Log.v(TAG, "HH2: Requesting permissions");
            activityResultLauncher.launch(permissionsList.get(index));
        });
        builder.show();
    }

    // THis method just summarizes the results of the permissions.
    @SuppressLint("NewApi")
    private void handlePermissionSummary()
    {
        boolean connectOk = (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED);
        boolean scanOk = (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED);
        boolean locationOk = (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED);
        boolean backgroundOk = (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED);

        Log.d(TAG, "HH2: BLUETOOTH_CONNECT Permissions are " + connectOk);
        Log.d(TAG, "HH2: BLUETOOTH_SCAN Permissions are " + scanOk);
        Log.d(TAG, "HH2: ACCESS_FINE_LOCATION Permissions are " + locationOk);
        Log.d(TAG, "HH2: ACCESS_BACKGROUND_LOCATION Permissions are " + backgroundOk);

        String message = "";
        if (!connectOk && isVersionS_Plus)
        {
            message = "<p><b>Bluetooth Connect permissions not given.</b> You will be unable to find and connect to Bluetooth Low Energy devices</p>";
        }
        if (!scanOk && isVersionS_Plus)
        {
            message = "<p><b>Bluetooth Scan permissions not given.</b> You will be unable to find and connect to Bluetooth Low Energy devices</p>";
        }
        if (!locationOk && !isVersionS_Plus)
        {
            message = "<p><b>Location permissions not given.</b> You will be unable to find and connect to Bluetooth Low Energy devices</p>";
        }
        if (!backgroundOk && isVersionO_Plus)
        {
            message = message + "<p><b>Background permissions not given.</b> Operations with Bluetooth Low Energy devices will only work " +
                    "while Health@Home PHG is visible on the screen.</p>";
        }
        if (!message.isEmpty())
        {
            message = message + "<p>Remedies:<br>1. Restart Health@Home PHG.<br>2. Set permissions directly in the Android Settings menu<br>" +
                    "3. Uninstall and re-install Health@Home PHG</p>";
            final AlertDialog.Builder builder =
                    new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.Theme_AppCompat_Light));
            builder.setTitle("Health@Home not given certain permissions!");
            if (isVersionN_Plus)
            {
                builder.setMessage(Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY));
            }
            else
            {
                builder.setMessage(Html.fromHtml(message));
            }
            builder.setPositiveButton(android.R.string.ok, null);
            builder.setOnDismissListener(dialog ->
            {
                Log.d(TAG, "Starting Login");
               // setLoginScreen(); // Do whatever you would do after permissions are handled
            });
            builder.show();
            return;
        }
        Log.d(TAG, "Starting Login");
      //  setLoginScreen(); // Do whatever you would do after permissions are handled
    }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61909313

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档