Android Runtime权限示例
欢迎使用android运行时权限示例。
随着Android 6.0 Marshmallow的引入,Google改变了应用程序处理权限的方式。
在本教程中,我们将研究引入的新android运行时权限以及如何处理它们。
如果处理不当,可能会导致应用程序崩溃。
什么是Android运行时权限?
随着Android 6.0(SDK 23)的引入,在有必要使用时会提示用户在运行时输入一些特定权限。
因此,我们想到的第一个问题是–旧版应用程序是否可以在Android Marshmallow上运行?如果targetSdkVersion为22或者更小,答案是肯定的。
因此,Android运行时权限支持向后兼容。
现在这并不意味着我们可以通过将sdk版本设置为22来使用旧的权限模型。
使用棉花糖的用户可以从"设置"->"应用"中撤消危险权限(稍后将讨论危险权限和普通权限)。
->权限。
在我们尝试调用某些需要用户尚未授予的权限的函数的情况下,该函数将突然抛出Exception(java.lang.SecurityException
),这将导致应用程序崩溃。
因此,我们需要在我们的应用程序中实现这个新的android权限模型。
危险和正常的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);
它返回PERMISSION_GRANTED或者PERMISSION_DENIED的整数值。
注意:如果用户拒绝在应用程序中很重要的权限,则使用" shouldShowRequestPermissionRationale(StringPermission);"来描述用户对权限的需求。
让我们开发一个应用程序,检查许可是否已经存在。
如果不是,则在运行时请求。
Android Runtime 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.theitroad.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.theitroad.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(); } }
注意:将在运行时要检查的权限添加到应用程序标签上方的列表文件中,如下所示:
<uses-permission android:name="android.permission.CAMERA" <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
在上面的代码中,检查和请求的两个权限是CAMERA和LOCATION。
导入静态权限完整类名使我们可以只编写PERMISSION对象,而不编写完全限定的路径。
checkPermission()
对每个权限调用checkSelfPermission。
requestPermission()
调用ActivityCompat.requestPermissions(this,new String [] {ACCESS_FINE_LOCATION,CAMERA},PERMISSION_REQUEST_CODE);
。
onRequestPermissionsResult检查是否授予权限。
在我们的代码中,如果未同时授予两个权限,则会弹出一个警告对话框,显示强制要求该权限的需求。
为此,应调用" shouldShowRequestPermissionRationale(String权限)",这将显示一个警告对话框,显示对权限的需求。
您可以从"设置"->"应用程序"->"权限"手动撤消权限。
注意:特定于运行时权限的方法仅自API 23起可用。
因此,在每种方法中都会检查以下条件:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)