Android 运行时权限的例子

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

什么是Android运行时权限?

随着Android 6.0的推出(SDK 23),当需要使用某些特定权限时,用户会在运行时收到提示。因此,我们首先要考虑的问题是 – 老版本的应用程序能在Android Marshmallow上运行吗?答案是,如果目标SDK版本为22或更低,则可以。因此,Android运行时权限支持向后兼容。现在,这并不意味着我们可以通过将SDK版本设置为22来使用旧的权限模型。Marshmallow用户可以从设置->应用程序->权限中撤销危险权限(稍后我们会讨论危险权限和普通权限)。在尝试调用需要用户尚未授予的权限的某个函数时,该函数将突然抛出异常(java.lang.SecurityException),导致应用程序崩溃。因此,我们需要在我们的应用程序中实现这个新的Android权限模型。

危险和常规安卓权限

Android将一些权限标记为危险权限,而将另一些标记为普通权限。这两类权限的共同之处在于需要在清单文件中进行定义。从Android 6.0开始,系统只会在运行时检查危险权限,而不会检查普通权限。例如,android.permission.INTERNET是一个普通权限。危险权限被分为不同的类别,以便用户更容易理解他们允许应用程序做什么。如果用户接受了一个组/类别中的一个权限,那么他们就接受了整个组。android.permission.FINE_LOCATION和android.permission.COARSE_LOCATION是危险权限的示例。启用其中任何一个位置权限就会启用所有位置权限。

请求 Android 运行时权限

方法 requestPermissions(String[] permissions, int requestCode); 是一个公共方法,用于请求危险权限。我们可以通过传递一个字符串数组来请求多个危险权限。注意:Android权限属于两个不同的组,将分别向用户显示每个组的对话框。如果权限属于同一组,则只会显示一个对话框提示。请求的结果将传递给方法 onRequestPermissionResult。例如:假设我们想要在应用程序中访问相机和位置。这两个权限都属于危险权限。在应用程序启动时,我们将显示一个提示,请求访问这些权限。让我们将权限添加到一个字符串数组中,如下所示调用 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;

    }

}

现在我们不希望用户重复接受他已经接受过的权限。即使权限之前已经被授予,仍然需要再次检查以确保用户没有后来撤销该权限。为此,需要在每个权限上调用以下方法。

checkSelfPermission(String perm);

返回一个整数值,表示是否授予权限。注意:如果用户拒绝了应用中的关键权限,则应使用shouldShowRequestPermissionRationale(String permission)来说明需要权限的原因。让我们开发一个应用程序来检查权限是否已经存在。如果不存在,则在运行时请求权限。

Android Runtime Permissions 项目结构

android runtime permissions project

Android运行时权限代码

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.Olivia.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>

MainActivity.java的定义如下。

package com.Olivia.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();
    }

}

注意:在Manifest文件中,将需要在运行时检查的权限添加到应用程序标签之上。

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

在上述代码中,检查和请求的两个权限是相机和位置。导入静态权限完整类名允许我们只写入 PERMISSION 对象,而不是完全限定的路径。checkPermission() 方法调用每个权限的 checkSelfPermission() 方法。requestPermission() 方法调用 ActivityCompat.requestPermissions(this, new String[]{ACCESS_FINE_LOCATION, CAMERA}, PERMISSION_REQUEST_CODE);。onRequestPermissionsResult() 方法检查权限是否被授予。在我们的代码中,如果两个权限都没有被授予,弹出一个警示对话框显示请求权限的必要性。为了实现这一点,会调用 shouldShowRequestPermissionRationale(String permission) 方法,该方法会显示请求权限的警示对话框。您可以在设置->应用程序->权限中手动撤销权限。注意:运行时权限相关的方法仅在 API 23 及以上版本中可用。因此,在每个方法中都会检查以下条件:

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

以下是Android运行时权限示例应用的输出结果。本教程到此结束。您可以通过以下链接下载最终的Android运行时权限项目。

下载Android运行时权限示例项目

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

请参考这个链接:https://developer.android.com/training/permissions/requesting.html

发表回复 0

Your email address will not be published. Required fields are marked *


广告
将在 10 秒后关闭
bannerAds