欢迎使用Android运行时权限示例。随着Android 6.0棉花糖 的推出,谷歌改变了应用程序处理权限的方式。在本教程中,我们将研究引入的新的Android运行时权限以及如何处理它们。如果处理不当,可能会导致应用程序崩溃。
什么是Android运行时权限?
随着Android 6.0(SDK 23)的引入,当用户需要使用时,会在运行时提示他们需要一些特定的权限。因此,我们想到的第一个问题是--旧的应用程序会在Android棉花糖上运行吗?如果目标SdkVersion为22或更低,则答案是是 。因此,Android运行时权限支持向后兼容。现在,这并不意味着我们可以通过将SDK版本设置为22来使用旧的权限模型。使用棉花糖的用户可以从设置->应用->权限中撤销危险权限(我们稍后将讨论危险权限和正常权限)。如果我们试图调用一些需要用户尚未授予权限的函数,该函数将突然抛出一个异常(java.lang.SecurityException
),这将导致应用程序崩溃。因此,我们需要在应用程序中实现这个新的Android权限模型。
危险和正常的Android权限
Android将一些权限定义为危险权限,另一些定义为正常权限。这两种类型的共同点是它们需要在Manifest文件中定义。从Android 6.0开始,只在运行时检查危险权限,而不检查正常权限。普通权限的一个例子是android.permission.INTERNET
。危险权限被分成不同的类别,以便用户更容易理解他们允许应用程序执行的操作。如果用户接受组/类别中的一个权限,则他们接受整个组。例如,android.permission.FINE_Location
和android.permission.COARSE_Location
就是危险权限。启用任何位置权限都会启用所有权限。
请求Android运行时权限
方法questPermises(String[]Permittions,int questCode);
是一个公共方法,用于请求危险权限。我们可以通过传递权限字符串数组来请求多个危险权限。注意 :Android权限属于两个不同的组,每个组都会有一个单独的对话框提示用户。如果它们属于同一组,则只会显示一个对话框提示。请求的结果将传入onRequestPermissionResult
方法。例如:假设我们想要访问应用程序中的摄像头和位置。两者都是危险的权限。当应用程序启动时,我们将显示一个提示,请求访问这些权限。让我们将权限添加到字符串数组中,并调用请求权限,如下所示:
1String[] perms = {"android.permission.FINE_LOCATION", "android.permission.CAMERA"};
2
3int permsRequestCode = 200;
4requestPermissions(perms, permsRequestCode);
5
6@Override
7public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults){
8
9 switch(permsRequestCode){
10
11 case 200:
12
13 boolean locationAccepted = grantResults[0]==PackageManager.PERMISSION_GRANTED;
14 boolean cameraAccepted = grantResults[1]==PackageManager.PERMISSION_GRANTED;
15
16 break;
17
18 }
19
20}
现在,我们不希望用户继续接受他已经接受的权限。即使该权限先前已被授予,也必须再次检查以确保用户随后没有撤销该权限。为此,需要对每个权限调用以下方法。
1checkSelfPermission(String perm);
返回整数值PERSISSION_GRANDED 或** PERSISSION_DENIED** 。** 注意** :如果用户拒绝了APP中的关键权限,则使用shouldShowRequestPermissionRationale(字符串权限);
来描述用户对该权限的需求。让我们开发一个应用程序来检查权限是否已经存在。如果不是,则在运行时请求它。
Android运行时权限项目结构
Android运行时权限-code
content_main.xml
包含两个按钮,分别用于检查和请求权限。
1<?xml version="1.0" encoding="utf-8"?>
2<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
3 xmlns:app="https://schemas.android.com/apk/res-auto"
4 xmlns:tools="https://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent"
7 android:paddingBottom="@dimen/activity_vertical_margin"
8 android:paddingLeft="@dimen/activity_horizontal_margin"
9 android:paddingRight="@dimen/activity_horizontal_margin"
10 android:paddingTop="@dimen/activity_vertical_margin"
11 app:layout_behavior="@string/appbar_scrolling_view_behavior"
12 tools:context="com.journaldev.runtimepermissions.MainActivity"
13 tools:showIn="@layout/activity_main">
14 <Button
15 android:id="@+id/check_permission"
16 android:layout_width="match_parent"
17 android:layout_centerInParent="true"
18 android:layout_height="wrap_content"
19 android:text="Check Permission"/>
20 <Button
21 android:id="@+id/request_permission"
22 android:layout_below="@+id/check_permission"
23 android:layout_width="match_parent"
24 android:layout_height="wrap_content"
25 android:text="Request Permission"/>
26</RelativeLayout>
MainActivity.java
定义如下。
1package com.journaldev.runtimepermissions;
2
3import android.content.DialogInterface;
4import android.content.pm.PackageManager;
5import android.os.Build;
6import android.os.Bundle;
7import android.support.design.widget.Snackbar;
8import android.support.v4.app.ActivityCompat;
9import android.support.v4.content.ContextCompat;
10import android.support.v7.app.AlertDialog;
11import android.support.v7.app.AppCompatActivity;
12import android.support.v7.widget.Toolbar;
13
14import android.view.View;
15import android.widget.Button;
16
17import static android.Manifest.permission.ACCESS_FINE_LOCATION;
18import static android.Manifest.permission.CAMERA;
19
20public class MainActivity extends AppCompatActivity implements View.OnClickListener {
21
22 private static final int PERMISSION_REQUEST_CODE = 200;
23 private View view;
24
25 @Override
26 protected void onCreate(Bundle savedInstanceState) {
27 super.onCreate(savedInstanceState);
28 setContentView(R.layout.activity_main);
29 Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
30 setSupportActionBar(toolbar);
31
32 Button check_permission = (Button) findViewById(R.id.check_permission);
33 Button request_permission = (Button) findViewById(R.id.request_permission);
34 check_permission.setOnClickListener(this);
35 request_permission.setOnClickListener(this);
36
37 }
38
39 @Override
40 public void onClick(View v) {
41
42 view = v;
43
44 int id = v.getId();
45 switch (id) {
46 case R.id.check_permission:
47 if (checkPermission()) {
48
49 Snackbar.make(view, "Permission already granted.", Snackbar.LENGTH_LONG).show();
50
51 } else {
52
53 Snackbar.make(view, "Please request permission.", Snackbar.LENGTH_LONG).show();
54 }
55 break;
56 case R.id.request_permission:
57 if (!checkPermission()) {
58
59 requestPermission();
60
61 } else {
62
63 Snackbar.make(view, "Permission already granted.", Snackbar.LENGTH_LONG).show();
64
65 }
66 break;
67 }
68
69 }
70
71 private boolean checkPermission() {
72 int result = ContextCompat.checkSelfPermission(getApplicationContext(), ACCESS_FINE_LOCATION);
73 int result1 = ContextCompat.checkSelfPermission(getApplicationContext(), CAMERA);
74
75 return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
76 }
77
78 private void requestPermission() {
79
80 ActivityCompat.requestPermissions(this, new String[]{ACCESS_FINE_LOCATION, CAMERA}, PERMISSION_REQUEST_CODE);
81
82 }
83
84 @Override
85 public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
86 switch (requestCode) {
87 case PERMISSION_REQUEST_CODE:
88 if (grantResults.length > 0) {
89
90 boolean locationAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
91 boolean cameraAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED;
92
93 if (locationAccepted && cameraAccepted)
94 Snackbar.make(view, "Permission Granted, Now you can access location data and camera.", Snackbar.LENGTH_LONG).show();
95 else {
96
97 Snackbar.make(view, "Permission Denied, You cannot access location data and camera.", Snackbar.LENGTH_LONG).show();
98
99 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
100 if (shouldShowRequestPermissionRationale(ACCESS_FINE_LOCATION)) {
101 showMessageOKCancel("You need to allow access to both the permissions",
102 new DialogInterface.OnClickListener() {
103 @Override
104 public void onClick(DialogInterface dialog, int which) {
105 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
106 requestPermissions(new String[]{ACCESS_FINE_LOCATION, CAMERA},
107 PERMISSION_REQUEST_CODE);
108 }
109 }
110 });
111 return;
112 }
113 }
114
115 }
116 }
117
118 break;
119 }
120 }
121
122 private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
123 new AlertDialog.Builder(MainActivity.this)
124 .setMessage(message)
125 .setPositiveButton("OK", okListener)
126 .setNegativeButton("Cancel", null)
127 .create()
128 .show();
129 }
130
131}
注意:在应用程序标签上方的Manifest文件中添加运行时需要检查的权限;
1<uses-permission android:name="android.permission.CAMERA" />
2<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
在上面的代码中,检查和请求的两个权限是摄像机和位置。导入静态权限完整类名允许我们只编写权限对象,而不是完全限定路径。check Permission()
调用每个权限上的check SelfPermission。questPermission()
调用ActivityCompat.questPermission(this,new字符串[]{ACCESS_FINE_LOCATION,CAMERA},PERMISSION_REQUEST_CODE);
。onRequestPermissionsResult
检查是否授予权限。在我们的代码中,如果这两个权限都没有被授予,则会弹出一个警告对话框,显示强制需要请求权限。为此,将调用shoudShowRequestPermissionRationale(字符串权限)
,这将调用一个警告对话框来显示需要权限。您可以在设置->应用->权限中手动撤销权限。注 :运行时权限的具体方法仅在API 23以后的版本中提供。因此,在每个方法中都会检查以下条件:
1if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
android运行时权限示例应用程序的输出如下所示。本教程到此结束。您可以从下面的链接下载最终的Android插件项目。
参考文献:https://developer.android.com/training/permissions/requesting.html