一、为什么需要动态申请权限?
在Android移动设备上,权限是一项非常重要的安全特性。应用需要获得用户授权才能访问特定的设备功能或用户信息。根据不同的功能,权限可分为正常权限和危险权限两种。
正常权限通常是指运行应用所必需的权限,如访问网络状态等。这些权限会在安装应用时自动授予,用户不需要进行确认。
而危险权限则是指对用户个人信息和设备重要功能进行访问的权限,比如读取联系人、读取短信等。这些权限需要用户明确授权才能使用。Android 6.0(API 23)引入了动态权限模型,允许用户在应用运行时动态地授权这些危险权限。
使用动态权限申请,能保护用户隐私安全,提高应用用户友好度,避免用户对应用的不信任感,增加用户与应用的互动,提高应用的用户活跃度,从而提高应用评分和推广度。
二、如何执行动态申请权限
Android虽然提供了权限管理,但是某些应用运行时可能需要并未在manifest文件中包含的新权限,因此需要动态申请权限。
如下是一个运用动态权限申请的应用示例,其实现为让用户在使用应用期间打开相机并捕捉照片的功能。
public class MainActivity extends AppCompatActivity { private static final int REQUEST_CAMERA_PERMISSION = 1; private static final int REQUEST_CAMERA = 2; private Camera mCamera; private boolean hasCameraPermission() { // Check if the Camera permission has been granted return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED; } private void requestCameraPermission() { // Request the Camera permission if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { new ConfirmationDialog().show(getFragmentManager(), FRAGMENT_DIALOG); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); } } private void requestCamera() { // Request to launch the Camera Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent, REQUEST_CAMERA); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (hasCameraPermission()) { requestCamera(); } else { requestCameraPermission(); } } }); // Open the camera when the app is launched if (hasCameraPermission()) { requestCamera(); } else { requestCameraPermission(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode) { case REQUEST_CAMERA_PERMISSION: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { requestCamera(); } else { Toast.makeText(this, "You need to grant permission to use the camera", Toast.LENGTH_SHORT).show(); } break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_CAMERA: if (resultCode == RESULT_OK) { // Save the captured image Bundle bundle = data.getExtras(); Bitmap bitmap = (Bitmap) bundle.get("data"); ImageView imageView = findViewById(R.id.image_view); imageView.setImageBitmap(bitmap); } break; } } public static class ConfirmationDialog extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final Fragment parent = getParentFragment(); return new AlertDialog.Builder(getActivity()) .setMessage("Need permission to use the camera") .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { FragmentCompat.requestPermissions(parent, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); } }) .setNegativeButton(android.R.string.cancel, null) .create(); } } }
上述代码中,首先定义了应用所需的危险权限“CAMERA”和requestCode,然后使用hasCameraPermission()判断是否获得授权。如果未获得权限,则使用requestCameraPermission()方法向系统发出权限请求,如果已获得授权,则使用requestCamera()方法请求打开相机。 当用户按下拍照按钮后,onActivityResult()会接收请求的结果。如果结果是OK,表示照片已捕捉到。否则,用户可能取消了该动作或者出现了问题。
三、优化动态申请权限的用户体验
尽管动态权限申请提升了应用的用户体验,但是在用户授权的途中,用户可能会遇到多次重复授权的问题,这会降低用户对应用的满意度。为了缓解用户对弹出请求的强烈反感及让用户更好的理解对应用所需授权的必要性,我们可以采取如下几种方式来优化用户体验。
1. 显示完整的证明
为了更好地避免用户对应用的不信任感,设备令生产商和厂商提供了“应用设置”中关于应用所需权限的描述。为了提高用户对权限描述的理解和透明度,我们可以在弹出框中显示完整的证明。
public class MainActivity extends AppCompatActivity { private void requestCameraPermission() { // Request the Camera permission if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { // Explain to the user why we need permission Snackbar.make(findViewById(android.R.id.content), "Need permission to use the camera for taking pictures", Snackbar.LENGTH_LONG).setAction("OK", new View.OnClickListener() { @Override public void onClick(View v) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); } }).show(); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); } } }
上述代码中,使用Snackbar进行证明说明,将对话框内容从简单的“A“更新为有用的描述。同时,添加了一个”OK”按钮来开始授权请求。
2. 在请求过程中展示进度
当系统请求权限时,等待是不可避免的。但是,我们可以在会话过程中显示一个进度条,以便用户有时间了解发生了什么。
public class MainActivity extends AppCompatActivity { private ProgressDialog mProgressDialog; private void requestCameraPermission() { // Show a progress bar while the app requests permission if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { // Explain to the user why we need permission showCameraPermissionExplanation(); } else { showProgressBar(); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); } } private void showProgressBar() { mProgressDialog = new ProgressDialog(this); mProgressDialog.setMessage("Requesting permission"); mProgressDialog.setCancelable(false); mProgressDialog.setIndeterminate(true); mProgressDialog.show(); } private void cancelProgressBar() { mProgressDialog.cancel(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); cancelProgressBar(); switch (requestCode) { case REQUEST_CAMERA_PERMISSION: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { requestCamera(); } else { Toast.makeText(this, "You need to grant permission to use the camera", Toast.LENGTH_SHORT).show(); } break; } } }
上述代码中,使用ProgressDialog来显示进度条。在permission请求结束后,使用cancelProgressBar()方法取消进度条,展示授权请求结果。同时,在onRequestPermissionsResult()中使用cancelProgressBar()取消进度条。
3. 向用户解释为什么需要特定的权限
当用户拒绝授权时,可以向用户展示为什么需要该权限,以便帮助解释需要的原因。
public class MainActivity extends AppCompatActivity { private void requestCameraPermission() { // Request the Camera permission if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { // Explain to the user why we need permission showCameraPermissionExplanation(); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); } } private void showCameraPermissionExplanation() { new AlertDialog.Builder(this).setTitle("Need permission to use the camera").setMessage("This app needs the camera permission in order to take pictures.").setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); } }).setNegativeButton("Cancel", null) .show(); } }
上述代码中,在shouldShowRequestPermissionRationale()返回true时,首先创建一个AlertDialog以向用户解释为什么需要权限,然后提供一个“OK”按钮,以便用户开始授权请求。
四、总结
采用动态权限申请方式,可以保护用户隐私安全,提高应用用户友好度,避免用户对应用的不信任感,增加用户与应用的互动,提高应用的用户活跃度, 从而提高应用评分和推广度。优化动态权限申请的用户体验,能缓解用户对弹出请求的反感,提高用户对应用的满意度。