如何在Android中询问Camera的运行时权限,运行时存储权限
Posted
技术标签:
【中文标题】如何在Android中询问Camera的运行时权限,运行时存储权限【英文标题】:How to ask runtime permissions for Camera in Android , Runtime storage permissions 【发布时间】:2017-07-05 16:18:48 【问题描述】:我正在做一个应用程序,通过单击按钮扫描条形码,它在 Lollipop 版本中运行良好。当我来到棉花糖时,它停止了工作。这是错误:
camerabase 连接到相机 0 时发生错误
它迫使我通过以下方式打开权限:
设置 --> 应用程序 --> 我的应用程序 --> 相机。
我的问题是如何在 Marshmallow 中自动允许我的应用程序使用摄像头权限,或者要求用户在运行时打开摄像头。屏幕截图:
【问题讨论】:
developer.android.com/training/permissions/requesting.html Android M - failed to check runtime permission的可能重复 Android marshmallow request permission?的可能重复 在这里你可以找到一个有用的方法来在Android中询问运行时权限handyopinion.com/ask-runtime-permission-in-kotlin-android 【参考方案1】:下面我编写了一个代码,用于授予相机的运行时权限,有一个字符串数组,您可以在其中根据运行时的需要授予多个请求。
public class MainActivity extends AppCompatActivity
private static final int PERMISSION_REQUEST_CODE = 200;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkPermission())
//main logic or main code
// . write your main code to execute, It will execute if the permission is already given.
else
requestPermission();
private boolean checkPermission()
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED)
// Permission is not granted
return false;
return true;
private void requestPermission()
ActivityCompat.requestPermissions(this,
new String[]Manifest.permission.CAMERA,
PERMISSION_REQUEST_CODE);
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
switch (requestCode)
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
Toast.makeText(getApplicationContext(), "Permission Granted", Toast.LENGTH_SHORT).show();
// main logic
else
Toast.makeText(getApplicationContext(), "Permission Denied", Toast.LENGTH_SHORT).show();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED)
showMessageOKCancel("You need to allow access permissions",
new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
requestPermission();
);
break;
private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener)
new AlertDialog.Builder(MainActivity.this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", null)
.create()
.show();
【讨论】:
【参考方案2】:这是实现多个或单个运行时权限的完整代码
第 1 步
在
manifest
中添加相机权限以及其他所需权限 权限
喜欢
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
第 2 步
声明这个变量
public static final int REQUEST_ID_MULTIPLE_PERMISSIONS= 7;
并在oncreate()
中调用此方法checkAndroidVersion()
private void checkAndroidVersion()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
checkAndRequestPermissions();
else
// code for lollipop and pre-lollipop devices
private boolean checkAndRequestPermissions()
int camera = ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.CAMERA);
int wtite = ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE);
int read = ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE);
List<String> listPermissionsNeeded = new ArrayList<>();
if (wtite != PackageManager.PERMISSION_GRANTED)
listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (camera != PackageManager.PERMISSION_GRANTED)
listPermissionsNeeded.add(Manifest.permission.CAMERA);
if (read != PackageManager.PERMISSION_GRANTED)
listPermissionsNeeded.add(Manifest.permission.READ_EXTERNAL_STORAGE);
if (!listPermissionsNeeded.isEmpty())
ActivityCompat.requestPermissions(getActivity(), listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
return true;
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults)
Log.d("in fragment on request", "Permission callback called-------");
switch (requestCode)
case REQUEST_ID_MULTIPLE_PERMISSIONS:
Map<String, Integer> perms = new HashMap<>();
// Initialize the map with both permissions
perms.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.CAMERA, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.READ_EXTERNAL_STORAGE, PackageManager.PERMISSION_GRANTED);
// Fill with actual results from user
if (grantResults.length > 0)
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
// Check for both permissions
if (perms.get(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED && perms.get(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
Log.d("in fragment on request", "CAMERA & WRITE_EXTERNAL_STORAGE READ_EXTERNAL_STORAGE permission granted");
// process the normal flow
//else any one or both the permissions are not granted
else
Log.d("in fragment on request", "Some permissions are not granted ask again ");
//permission is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permission
// // shouldShowRequestPermissionRationale will return true
//show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) || ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.CAMERA) || ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE))
showDialogOK("Camera and Storage Permission required for this app",
new DialogInterface.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
switch (which)
case DialogInterface.BUTTON_POSITIVE:
checkAndRequestPermissions();
break;
case DialogInterface.BUTTON_NEGATIVE:
// proceed with logic by disabling the related features or quit the app.
break;
);
//permission is denied (and never ask again is checked)
//shouldShowRequestPermissionRationale will return false
else
Toast.makeText(getActivity(), "Go to settings and enable permissions", Toast.LENGTH_LONG)
.show();
// //proceed with logic by disabling the related features or quit the app.
private void showDialogOK(String message, DialogInterface.OnClickListener okListener)
new AlertDialog.Builder(getActivity())
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", okListener)
.create()
.show();
【讨论】:
对我来说效果很好。谢谢!三星S6,安卓7.0【参考方案3】: if (ContextCompat.checkSelfPermission(getContext(),
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
if (ActivityCompat.shouldShowRequestPermissionRationale((Activity)
getContext(), Manifest.permission.CAMERA))
else
ActivityCompat.requestPermissions((Activity) getContext(),
new String[]Manifest.permission.CAMERA,
MY_PERMISSIONS_REQUEST_CAMERA);
【讨论】:
【参考方案4】:This sample Profile project demonstrates how to get Read Storage and Camera Permission in Android and also how to handle when the user selects DENY & DON'T ASK AGAIN.
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
registerStoragePermission()
registerGalleryLauncher()
registerCameraPermission()
registerCameraLauncher()
private fun registerCameraPermission()
requestCameraPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) granted ->
if (granted)
Log.d(TAG, "registerCameraPermission - Camera Permission Granted")
openCamera()
else
Log.d(TAG, "registerCameraPermission - Camera Permission NOT Granted")
requestCameraPermission()
private fun registerStoragePermission()
requestStoragePermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) granted ->
if (granted)
Log.d(TAG, "registerStoragePermission - Storage Permission Granted")
viewGallery()
else
Log.d(TAG, "registerStoragePermission - Storage Permission NOT Granted")
requestStoragePermission()
private fun registerCameraLauncher()
cameraLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) result ->
if (result.resultCode == Activity.RESULT_OK)
val data: Intent? = result.data
if (data == null)
return@registerForActivityResult
val extras = data.extras
imageBitmap = extras!!["data"] as Bitmap
file = FileUtils.createFile(requireContext(),
getString(R.string.app_name),
"my_profile_image.png"
)
//FileUtils.saveBitmap(imageBitmap, file);
val imageLocalPath = FileUtils.saveImageToInternalStorage(file, imageBitmap)
SharedPreferencesUtils.setProfilePath(requireActivity(), imageLocalPath)
profileFragmentBinding.imageViewCircleNoStroke.setImageBitmap(imageBitmap)
profileFragmentBinding.imageViewCircleNoStroke.setScaleType(ImageView.ScaleType.CENTER_CROP)
private fun registerGalleryLauncher()
galleryLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) result ->
if (result.resultCode == Activity.RESULT_OK)
val data: Intent? = result.data
if (data == null)
return@registerForActivityResult
val uri = data.data
var imageLocalPath = File(FileUtils.getPathReal(requireActivity(), uri!!))
file = imageLocalPath.absoluteFile
SharedPreferencesUtils.setProfilePath(requireActivity(), imageLocalPath.absolutePath)
Glide.with(requireActivity()).load(uri)
.into(profileFragmentBinding.imageViewCircleNoStroke)
profileFragmentBinding.imageViewCircleNoStroke.setScaleType(ImageView.ScaleType.CENTER_CROP)
private fun showImageUploadOptions()
val mDialog = activity.let Dialog(it!!)
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
mDialog.setContentView(R.layout.dialog_profile_image_option)
mDialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
//val mAlertMessageTv = mDialog.findViewById<View>(R.id.id_alert_tv) as TextView
//mAlertMessageTv.text = message
galleryLl = mDialog.findViewById<View>(R.id.id_gallery_ll) as LinearLayout
cameraLl = mDialog.findViewById<View>(R.id.id_camera_ll) as LinearLayout
removePhotoLl = mDialog.findViewById<View>(R.id.id_remove_photo_ll) as LinearLayout
galleryLl.setOnClickListener
CallStoragePermission()
mDialog.dismiss()
cameraLl.setOnClickListener
CallCameraPermission()
mDialog.dismiss()
removePhotoLl.setOnClickListener
CallRemovePhoto()
mDialog.dismiss()
mDialog.setCancelable(true)
mDialog.show()
val metrics = resources.displayMetrics
val width = metrics.widthPixels
val height = metrics.heightPixels
mDialog.window!!.setLayout(
width,
LinearLayout.LayoutParams.WRAP_CONTENT
)
fun CallStoragePermission()
if (!Status_checkReadExternalStoragePermission())
requestStoragePermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
else
viewGallery()
private fun Status_checkReadExternalStoragePermission(): Boolean
val permissionState = ActivityCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.READ_EXTERNAL_STORAGE
)
return permissionState == PackageManager.PERMISSION_GRANTED
private fun requestCameraPermission()
when
ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED ->
Log.d(TAG, "requestCameraPermission - Camera Permission Granted")
openCamera()
// The permission is granted
// you can go with the flow that requires permission here
shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) ->
// This case means user previously denied the permission
// So here we can display an explanation to the user
// That why exactly we need this permission
Log.d(TAG, "requestCameraPermission - Camera Permission NOT Granted")
showPermissionAlert(
getString(R.string.camera_permission),
getString(R.string.camera_permission_denied),
getString(R.string.ok_caps),
getString(R.string.cancel_caps)
) requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
else ->
// Everything is fine you can simply request the permission
showPermissionAlert(
getString(R.string.camera_permission),
getString(R.string.camera_permission_denied),
getString(R.string.settings_caps),
getString(R.string.cancel_caps)
)
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts(
"package",
BuildConfig.APPLICATION_ID, null
)
intent.data = uri
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
private fun requestStoragePermission()
when
ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED ->
Log.d(TAG, "requestStoragePermission - Storage Permission Granted")
viewGallery()
// The permission is granted
// you can go with the flow that requires permission here
shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE) ->
// This case means user previously denied the permission
// So here we can display an explanation to the user
// That why exactly we need this permission
Log.d(TAG, "requestStoragePermission - Storage Permission NOT Granted")
showPermissionAlert(
getString(R.string.read_storage_permission_required),
getString(R.string.storage_permission_denied),
getString(R.string.ok_caps),
getString(R.string.cancel_caps)
) requestStoragePermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
else ->
// Everything is fine you can simply request the permission
showPermissionAlert(
getString(R.string.read_storage_permission_required),
getString(R.string.storage_permission_denied),
getString(R.string.settings_caps),
getString(R.string.cancel_caps)
)
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts(
"package",
BuildConfig.APPLICATION_ID, null
)
intent.data = uri
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
private fun showPermissionAlert(
title: String,
message: String,
ok: String,
cancel: String,
function: () -> Unit
)
val mDialog = requireActivity().let Dialog(it)
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
mDialog.setContentView(R.layout.dialog_permission_alert)
mDialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
val mTitleTv = mDialog.findViewById<View>(R.id.id_title_tv) as AppCompatTextView
mTitleTv.text = title
val mMessageTv = mDialog.findViewById<View>(R.id.id_message_tv) as AppCompatTextView
mMessageTv.text = message
val mNoBtn = mDialog.findViewById<View>(R.id.no_btn) as AppCompatTextView
mNoBtn.text = cancel
val mYesBtn = mDialog.findViewById<View>(R.id.yes_btn) as AppCompatTextView
mYesBtn.text = ok
mYesBtn.setOnClickListener
function.invoke()
mDialog.dismiss()
mNoBtn.setOnClickListener mDialog.dismiss()
mDialog.setCancelable(true)
mDialog.show()
val metrics = resources.displayMetrics
val width = metrics.widthPixels
val height = metrics.heightPixels
mDialog.window!!.setLayout(
width,
LinearLayout.LayoutParams.WRAP_CONTENT
)
fun viewGallery()
val intentDocument = Intent(Intent.ACTION_GET_CONTENT)
intentDocument.type = "image/*"
intentDocument.putExtra(
Constants.REQUEST_CODE,
Constants.REQUEST_PHOTO_FROM_GALLERY
)
galleryLauncher.launch(intentDocument)
fun openCamera()
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
takePictureIntent.putExtra(
Constants.REQUEST_CODE,
Constants.REQUEST_PERMISSIONS_REQUEST_CODE_CAMERA
)
cameraLauncher.launch(takePictureIntent)
fun CallCameraPermission()
if (!Status_checkCameraPermission())
requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
else
openCamera()
private fun Status_checkCameraPermission(): Boolean
val camera = ActivityCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.CAMERA
)
return camera == PackageManager.PERMISSION_GRANTED
【讨论】:
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review @Tomerikoo - 谢谢,添加了代码的基本部分...【参考方案5】:RxPermission 是向用户请求权限的最佳库。
对于相机权限,解决方法是这样的。
1) 首先在您的manifest.xml
中添加这些权限(或您需要的权限)。
<uses-permission android:name="android.permission.CAMERA" />
2) 然后在您的活动中向用户询问运行时许可。
RxPermissions rxPermissions = new RxPermissions(this);
rxPermissions
.request(Manifest.permission.CAMERA) // ask single or multiple permission once
.subscribe(granted ->
if (granted)
// All requested permissions are granted
else
// At least one permission is denied
);
将此库添加到您的build.gradle
allprojects
repositories
...
maven url 'https://jitpack.io'
dependencies
implementation 'com.github.tbruyelle:rxpermissions:0.10.1'
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
这不容易吗?
【讨论】:
【参考方案6】:清单.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
在你的活动中调用它:
handlePermissions(new String[]
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
);
也在你的活动中:
private void handlePermissions(String[] permissions)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
ArrayList<String> notGrantedPerms = new ArrayList<>();
for (String p : permissions)
if (this.checkSelfPermission(p) != PackageManager.PERMISSION_GRANTED)
notGrantedPerms.add(p);
permissions = notGrantedPerms.toArray(new String[0]);
if (permissions != null && permissions.length > 0)
this.requestPermissions(permissions, 701);
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 701)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
for (String p : permissions)
String msg = "";
if (this.checkSelfPermission(p) == PackageManager.PERMISSION_GRANTED)
msg = "Permission Granted for " + p;
else
msg = "Permission not Granted for " + p;
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
【讨论】:
【参考方案7】:void AutoRequestAllPermissions()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)return;
PackageInfo info = null;
try
info = getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), PackageManager.GET_PERMISSIONS);
catch (PackageManager.NameNotFoundException e)
e.printStackTrace();
if(info==null)return;
String[] permissions = info.requestedPermissions;
boolean remained = false;
for (String permission : permissions)
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED)
remained = true;
if(remained)
requestPermissions(permissions, 0);
这段代码-
-
自动从清单中读取所有权限
然后检查是否未授予任何权限
然后请求剩余的权限
【讨论】:
最简单的解决方案!【参考方案8】:这可能会有所帮助:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
if(ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.CAMERA))
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(context);
alertBuilder.setCancelable(true);
alertBuilder.setTitle("Permission necessary");
alertBuilder.setMessage("CAMERA is necessary");
alertBuilder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener()
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public void onClick(DialogInterface dialog, int which)
ActivityCompat.requestPermissions((Activity) context,
new String[]Manifest.permission.CAMERA, MY_PERMISSIONS_REQUESTS);
);
AlertDialog alert = alertBuilder.create();
alert.show();
else
ActivityCompat.requestPermissions((Activity) context, new String[]Manifest.permission.CAMERA, MY_PERMISSIONS_REQUESTS);
return false;
else
return true;
MY_PERMISSIONS_REQUESTS
是请求代码的最终值。
它对我来说很好用。
【讨论】:
【参考方案9】:在清单文件中定义它之后,比原生解决方案更友好的替代方案是使用 Aaper:https://github.com/LikeTheSalad/aaper,如下所示:
@EnsurePermissions(permissions = [Manifest.permission.CAMERA])
private fun takePhoto()
// Your code that needs the camera permission granted.
免责声明,我是 Aaper 的创造者。
【讨论】:
【参考方案10】:Android 团队提供了一种使用 registerForActivityResult 请求权限的新方法,
<uses-permission
android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
定义一个对象来请求权限,并在
callback
private val requestPermissionsLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) permissions ->
if (permissions.all it.value )
Toast.makeText(
this,
"You have obtained the required permissions",
Toast.LENGTH_LONG
).show()
else Toast.makeText(
this,
"You have not accepted all the permissions",
Toast.LENGTH_LONG
).show()
要请求权限,请执行以下操作,您可以添加任何您认为更好的位置:
requestPermissionsLauncher.launch(
arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
)
【讨论】:
以上是关于如何在Android中询问Camera的运行时权限,运行时存储权限的主要内容,如果未能解决你的问题,请参考以下文章
如何忘记 Android M 运行时权限对话框中的“不再询问”选项
Android NotificationChannel 在运行时询问多个频道的权限?