Android Runtime权限示例

Welcome to android runtime permissions example. With the introduction of Android 6.0 Marshmallow, Google has changed the way permissions are handled by the app. In this tutorial we’ll look into the new android runtime permissions that are introduced and how to handle them. If not handled properly, it can cause application crashes.

欢迎使用android运行时权限示例。 随着Android 6.0 Marshmallow的引入,Google改变了应用程序处理权限的方式。 在本教程中,我们将研究引入的新android运行时权限以及如何处理它们。 如果处理不当,可能会导致应用程序崩溃。

什么是Android运行时权限? (What are Android Runtime Permissions?)

With the introduction of Android 6.0 (SDK 23), users are prompted for some specific permissions at runtime when they become necessary to use.

随着Android 6.0(SDK 23)的引入,在用户有必要使用时会提示他们在运行时提供某些特定权限。

So the first question that comes to our mind is – Will the older apps run on Android Marshmallow? The answer is yes if the targetSdkVersion is 22 or less.

因此,我们想到的第一个问题是–旧版应用程序是否可以在Android Marshmallow上运行? 如果targetSdkVersion为22或更小,答案是肯定的。

Thus android runtime permissions support backward compatibility. Now this doesn’t mean that we can work with old model of permissions by setting the sdk version to 22. A user using Marshmallow can revoke the dangerous permissions (we’ll discuss the dangerous and normal permissions later) from the Settings->Apps->Permissions. In the case we try to call some function that requires a permission which user has not granted yet, the function will suddenly throw an Exception(java.lang.SecurityException) that will lead to the application crashing. Hence we need to implement this new android permissions model in our application.

因此,Android运行时权限支持向后兼容。 现在,这并不意味着我们可以通过将sdk版本设置为22来使用旧的权限模型。使用棉花糖的用户可以从Settings-> Apps撤消危险权限(我们将在以后讨论危险和普通权限) ->权限。 在我们尝试调用某些需要用户尚未授予的权限的函数的情况下,该函数将突然抛出Exception( java.lang.SecurityException ),这将导致应用程序崩溃。 因此,我们需要在我们的应用程序中实现这个新的android权限模型。

危险和正常的android权限 (Dangerous and Normal android permissions)

Android defines some permissions as dangerous and some as normal. The common thing in both the types is that they need to be defined in the Manifest file.

Android将某些权限定义为危险权限,将某些权限定义为正常权限。 这两种类型的共同点是它们需要在清单文件中定义。

From Android 6.0 only dangerous permissions are checked at runtime, normal permissions are not. An example of a normal permission is android.permission.INTERNET.

从Android 6.0起,只有危险权限会在运行时检查,而普通权限则不会。 普通权限的示例是android.permission.INTERNET

Dangerous permissions are grouped into categories that make it easier for the user to understand what they are allowing the application to do. If the user accepts one permission in a group/category they accept the entire group. An example of dangerous permission is android.permission.FINE_LOCATION and android.permission.COARSE_LOCATION. Enabling anyone of the location permissions enables all.

危险权限分为几类,使用户更容易理解他们允许应用程序执行的操作。 如果用户在组/类别中接受一个权限,则他们将接受整个组。 危险许可的示例是android.permission.FINE_LOCATIONandroid.permission.COARSE_LOCATION 。 启用任何位置权限都将全部启用。

请求Android运行时权限 (Requesting Android Runtime Permissions)

The method requestPermissions(String[] permissions, int requestCode); is a public method that is used to request dangerous permissions. We can ask for multiple dangerous permissions by passing a string array of permissions.

方法requestPermissions(String[] permissions, int requestCode); 是用于请求危险权限的公共方法。 我们可以通过传递权限的字符串数组来请求多个危险权限。

Note: Android Permissions belonging to two different groups would prompt the user with an individual dialog for each of them. If they belong to the same group, then only one dialog prompt would be displayed. The results of the requests will be passed into the method onRequestPermissionResult.

注意 :属于两个不同组的Android权限会提示用户,每个组都有一个单独的对话框。 如果它们属于同一组,则将仅显示一个对话框提示。 请求的结果将传递到方法onRequestPermissionResult

Example : Let’s say we want to access the camera and location in our app. Both are dangerous permissions. We’ll display a prompt requesting access to these permissions when the application is launched. Let’s add the permissions into a string array and call the requestPermissions as shown below:

示例:假设我们要访问应用程序中的摄像头和位置。 两者都是危险的权限。 启动应用程序时,我们将显示提示,要求访问这些权限。 让我们将权限添加到字符串数组中,然后调用requestPermissions,如下所示:

String[] perms = {"android.permission.FINE_LOCATION", "android.permission.CAMERA"};

int permsRequestCode = 200; 
requestPermissions(perms, permsRequestCode);

@Override
public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults){

    switch(permsRequestCode){

        case 200:

            boolean locationAccepted = grantResults[0]==PackageManager.PERMISSION_GRANTED;
            boolean cameraAccepted = grantResults[1]==PackageManager.PERMISSION_GRANTED;

            break;

    }

}

Now we don’t want the user to keep accepting permissions that he’s already accepted. Even if the permission has been previously granted it is necessary to check again to be sure that the user did not later revoke that permission. For this the following method needs to be called on every permission.

现在,我们不希望用户继续接受他已经接受的权限。 即使先前已授予许可,也必须再次检查以确保用户以后没有撤消该许可。 为此,需要在每个权限上调用以下方法。

checkSelfPermission(String perm);

It returns an integer value of PERMISSION_GRANTED or PERMISSION_DENIED.

它返回一个整数值PERMISSION_GRANTEDPERMISSION_DENIED

Note: If a user declines a permission that is critical in the app, then shouldShowRequestPermissionRationale(String permission); is used to describe the user the need for the permission.

注意 :如果用户拒绝对应用程序至关重要的权限,则shouldShowRequestPermissionRationale(String permission); 用于描述用户对权限的需要。

Let’s develop an application which checks if the permission is already present. If not, then it’s requested at runtime.

让我们开发一个检查许可是否已经存在的应用程序。 如果不是,则在运行时请求它。

Android Runtime Permissions项目结构 (Android Runtime Permissions Project Structure)

Android Runtime PermissionsCode (Android Runtime PermissionsCode)

The content_main.xml contains the two buttons to check and request permissions.

content_main.xml包含两个按钮,用于检查和请求权限。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.journaldev.runtimepermissions.MainActivity"
    tools:showIn="@layout/activity_main">
    <Button
        android:id="@+id/check_permission"
        android:layout_width="match_parent"
        android:layout_centerInParent="true"
        android:layout_height="wrap_content"
        android:text="Check Permission"/>
    <Button
        android:id="@+id/request_permission"
        android:layout_below="@+id/check_permission"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Request Permission"/>
</RelativeLayout>

The MainActivity.java is defined as below.

MainActivity.java定义如下。

package com.journaldev.runtimepermissions;

import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;

import android.view.View;
import android.widget.Button;

import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.CAMERA;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final int PERMISSION_REQUEST_CODE = 200;
    private View view;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        Button check_permission = (Button) findViewById(R.id.check_permission);
        Button request_permission = (Button) findViewById(R.id.request_permission);
        check_permission.setOnClickListener(this);
        request_permission.setOnClickListener(this);


    }


    @Override
    public void onClick(View v) {

        view = v;

        int id = v.getId();
        switch (id) {
            case R.id.check_permission:
                if (checkPermission()) {

                    Snackbar.make(view, "Permission already granted.", Snackbar.LENGTH_LONG).show();

                } else {

                    Snackbar.make(view, "Please request permission.", Snackbar.LENGTH_LONG).show();
                }
                break;
            case R.id.request_permission:
                if (!checkPermission()) {

                    requestPermission();

                } else {

                    Snackbar.make(view, "Permission already granted.", Snackbar.LENGTH_LONG).show();

                }
                break;
        }

    }

    private boolean checkPermission() {
        int result = ContextCompat.checkSelfPermission(getApplicationContext(), ACCESS_FINE_LOCATION);
        int result1 = ContextCompat.checkSelfPermission(getApplicationContext(), CAMERA);

        return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
    }

    private void requestPermission() {

        ActivityCompat.requestPermissions(this, new String[]{ACCESS_FINE_LOCATION, CAMERA}, PERMISSION_REQUEST_CODE);

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSION_REQUEST_CODE:
                if (grantResults.length > 0) {

                    boolean locationAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
                    boolean cameraAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED;

                    if (locationAccepted && cameraAccepted)
                        Snackbar.make(view, "Permission Granted, Now you can access location data and camera.", Snackbar.LENGTH_LONG).show();
                    else {

                        Snackbar.make(view, "Permission Denied, You cannot access location data and camera.", Snackbar.LENGTH_LONG).show();

                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                            if (shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)) {
                                showMessageOKCancel("You need to allow access to both the permissions",
                                        new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                                    requestPermissions(new String[]{ACCESS_FINE_LOCATION, CAMERA},
                                                            PERMISSION_REQUEST_CODE);
                                                }
                                            }
                                        });
                                return;
                            }
                        }

                    }
                }


                break;
        }
    }


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

}

Note: Add the permissions that are to be checked at runtime in the Manifest file above the application tag as;

注意:在应用程序标签上方的清单文件中,将要在运行时检查的权限添加为;

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

In the above code the two permissions that are checked and requested are CAMERA and LOCATION.
Importing the static permission full class name allows us to write just the PERMISSION object instead of the fully qualified path.

在上面的代码中,检查和请求的两个权限是CAMERA和LOCATION。
导入静态权限完整类名使我们可以只编写PERMISSION对象,而不编写完全限定的路径。

checkPermission() calls the checkSelfPermission on each of the permissions.

checkPermission()在每个权限上调用checkSelfPermission。

requestPermission() calls
ActivityCompat.requestPermissions(this, new String[]{ACCESS_FINE_LOCATION, CAMERA}, PERMISSION_REQUEST_CODE);.

requestPermission()调用
ActivityCompat.requestPermissions(this, new String[]{ACCESS_FINE_LOCATION, CAMERA}, PERMISSION_REQUEST_CODE);

onRequestPermissionsResult checks if the permissions are granted or not. In our code if both the permissions are not granted an alert dialog is popped showing the mandatory need to request the permissions. To do that shouldShowRequestPermissionRationale(String permission) is invoked which invokes an alert dialog showing the need for the permissions. You can revoke the permissions manually from Settings->Apps->Permissions.

onRequestPermissionsResult检查是否授予权限。 在我们的代码中,如果未同时授予两个权限,则会弹出一个警告对话框,显示强制要求获得权限的必要条件。 为此, shouldShowRequestPermissionRationale(String permission)调用shouldShowRequestPermissionRationale(String permission) ,这将显示一个警告对话框,显示对权限的需求。 您可以从设置->应用程序->权限中手动撤消权限。

Note: The runtime permission specific methods are available only since API 23. Hence the following condition is checked at each of the methods :

注意 :特定于运行时权限的方法仅自API 23起可用。因此,在每种方法中都会检查以下条件:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)

The output of the android runtime permissions example application in action is given below.

android runtime permissions example

实际运行中的android运行时权限示例应用程序的输出如下。

This brings an end to this tutorial. You can download the final Android Runtime Permissions project from the link below.

本教程到此结束。 您可以从下面的链接下载最终的Android Runtime Permissions项目。

Reference: https://developer.android.com/training/permissions/requesting.html

参考: https : //developer.android.com/training/permissions/requesting.html

翻译自: https://www.journaldev.com/10409/android-runtime-permissions-example

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值