【问题标题】:How to ask for user permissions in Android 6如何在 Android 6 中请求用户权限
【发布时间】:2016-01-29 18:16:26
【问题描述】:

我对 Android 6 (Marshmallow) 中的新权限系统感到非常困惑。

我正在使用两个所谓的“危险权限” -

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

而且我在很多地方都使用这些权限。

我需要访问用户帐户来注册应用程序、发送反馈等。我还需要访问设备 ID 来注册应用程序。

我在名为util的Java类中编写了两个函数来获取邮件帐户列表和设备ID,并在AsyncTask和片段中使用这些函数。

现在,我完全不知所措,如何请求这些权限!我应该在函数中询问还是每次调用这些函数时询问?而在 AsyncTask 中,我怎样才能得到响应呢?

请帮忙。

【问题讨论】:

    标签: android android-permissions android-6.0-marshmallow


    【解决方案1】:

    您不应该在 AsyncTask 中请求权限。事实上,您甚至不应该检索 deviceId 或其中的某些信息 - 将其作为参数传递。

    每个应用程序的设置都有“危险”权限列表及其状态。如果您的应用程序以 sdk 23 为目标,则默认情况下它们都被禁用。因此,当您使用需要此类权限的代码时,您需要检查它是否被授予,如果没有 - 请求它。

    最简单的方法是为这样的权限创建实用程序类:

    public final class PermissionUtils {
    
        private PermissionUtils() {
        }
    
        public static boolean checkPermissions(Context context, String... permissions) {
            for (String permission : permissions) {
                if (!checkPermission(context, permission)) {
                    return false;
                }
            }
            return true;
        }
    
        public static boolean checkPermission(Context context, String permission) {
            return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
        }
    
        public static boolean isDeviceInfoGranted(Context context) {
            return checkPermission(context, Manifest.permission.READ_PHONE_STATE);
        }
    
        public static void requestPermissions(Object o, int permissionId, String... permissions) {
            if (o instanceof Fragment) {
                FragmentCompat.requestPermissions((Fragment) o, permissions, permissionId);
            } else if (o instanceof Activity) {
                ActivityCompat.requestPermissions((AppCompatActivity) o, permissions, permissionId);
            }
        }
    }
    

    然后像这样使用它: (在您的片段/活动中)

    if (PermissionUtils.isDeviceInfoGranted(this)) {
        //get deviceId and proccess your code
    } else {
        String[] permissions = new String[]{READ_PHONE_STATE};
        PermissionUtils.requestPermissions(this, PHONE_STATE_PERMISSION_ID, permissions);
    }
    

    在您的 AppCompatActivity 中覆盖权限结果的处理程序或实现 OnRequestPermissionsResultCallback 接口:

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case PHONE_STATE_PERMISSION_ID:
                boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
                if (granted) {
                    //get deviceId and proccess your code
                } else {
                    //nobody knows what to do
                }
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
    

    如您所见,我们还有一个问题 - 如果用户拒绝许可,该怎么办?作为一个变体,我们可以显示解释对话框。或者(可能更好)仅在入职屏幕后请求权限。

    【讨论】:

    • 关于你回答的最后一部分,我也想知道谷歌的工程师是怎么想的!我认为这就是人们迁移到苹果的原因!我认为 Google 工程师甚至不知道如何使用这个新实现!!!!
    • 事实上,代码中没有什么复杂的——但最大的问题在于逻辑。 Android 6 给开发者带来了很多痛苦(权限、打盹模式)。但是 Apple 中的权限模型非常相似,所以你在这里是不正确的 :)
    • 还有一件事,我在 Manifest.permissions.Read_phone_State 中遇到错误我导入了 App Manifest,而 READ_PHONE_STATE 未解决
    • 全名是android.Manifest.permission.READ_PHONE_STATE 我刚刚导入为静态字段;导入静态 android.Manifest.permission.READ_PHONE_STATE
    • 抱歉打扰了,但我是新手 :-( 我的应用的 minSDK 是 9,我无法使用 Support v13,所以使用 FragmentCompat 是个问题。有什么解决方案吗?
    【解决方案2】:

    首先你必须在你的activity/fragment中实现以下方法:

    @Override
    public void onRequestPermissionsResult(int requestCode,@NonNull String permissions[], @NonNull int[] grantResults) {
        switch (requestCode) {
            case Permissions.READ_CONTACTS: { //Permissions.READ_CONTACTS is an int constant
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    getContactsFromPhone();
                }
            }
        }
    }
    

    然后在您的 onclick 中获取此联系人,您应该询问您是否有此权限:

        if (ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(activity,
                    new String[]{Manifest.permission.READ_CONTACTS}, Permissions.READ_CONTACTS); //Permissions.READ_CONTACTS is an int constant
            return false;
        } else {
           getContactsFromPhone();
        }
    

    【讨论】:

    • 异步任务呢?如果我在服务中这样做会怎样?
    【解决方案3】:

    1) 是的,您应该在每次调用这些函数时检查是否授予了权限。
    2)您可以从主线程检查和请求权限。我认为从 AsyncTask 检查和请求权限不是好方法,因为权限请求是一个对话框,您必须等待 asynctask 线程,直到您得到用户响应。尝试从主线程检查权限,获取用户响应,然后,如果授予权限,则启动您的异步任务。

    【讨论】:

      【解决方案4】:

      Dexter 是一个 Android 库,可简化运行时请求权限的过程。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-11-19
        • 2016-11-12
        • 1970-01-01
        • 1970-01-01
        • 2019-11-27
        • 1970-01-01
        • 2012-06-07
        • 1970-01-01
        相关资源
        最近更新 更多