安卓:权限拒绝:使用被撤销的权限android.permission.CAMERA启动Intent。

53

我正在尝试在我的应用程序中启动一个ACTION_IMAGE_CAPTURE活动以拍摄照片,但是我遇到了主题中的错误。

堆栈轨迹:

FATAL EXCEPTION: main
Process: il.ac.shenkar.david.todolistex2, PID: 3293
java.lang.SecurityException: Permission Denial: starting Intent { act=android.media.action.IMAGE_CAPTURE cmp=com.google.android.GoogleCamera/com.android.camera.CaptureActivity } from ProcessRecord{22b0eb2 3293:il.ac.shenkar.david.todolistex2/u0a126} (pid=3293, uid=10126) 
with revoked permission android.permission.CAMERA

在manifest.xml文件中添加了相机权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />

这里是打开相机的调用:

RadioGroup radioGroup = (RadioGroup) findViewById(R.id.statusgroup);
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId)
        {
            RadioButton rb = (RadioButton) findViewById(R.id.donestatusRBtn);
            if(rb.isChecked())
            {
                Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
                    startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
                }
            }
        }
    });

1
可能是[Android M相机意图+权限错误?](https://dev59.com/Pek6XIcBkEYKwwoYEf4H)的重复问题。 - Doug Stevenson
@DougStevenson,这是一台Nexus 5手机,它在这个设备上发生了吗? - David Faizulaev
1
这不是关于设备的问题,而是关于在Android M中所做的更改。如果参考问题对您没有帮助,请随意忽略它。 - Doug Stevenson
12个回答

87

移除此权限

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

在Android 7上运行我的应用程序时,我遇到了这个错误。经过测试,我发现项目A中缺少用户权限,但是它在项目B中存在,而我只在Android 5设备上测试了该项目B。因此,我在项目B中删除了该权限,以便在针对Android 7的其他设备上运行它,最终成功打开。

此外,我添加了Android建议的FileProvider代码,链接在这里https://developer.android.com/training/camera/photobasics.html。希望这能有所帮助。


12
移除权限居然解决了需要权限的错误,真是奇怪!!! - sai
1
它可以在Android N上工作,但是请在您的清单中使用@Saveen的第一个答案作为权限。我已经测试过了。 - MrX
3
加上我的一份,你的答案是唯一一个对我有用的。不过这很奇怪! - Yahya
3
哇!真的有效了。虽然在开发的起始阶段,我就想在清单文件中添加这行代码。 - Ankit Dubey
2
但是我的应用程序既可以通过Intent调用相机,也可以使用内置相机。授权后,内置相机可正常工作;未授权时,Intent相机可正常工作。 - Arnold Brown
显示剩余2条评论

27

嗨,您可以在清单文件中使用这些权限和其他权限,

<uses-feature
    android:name="android.hardware.camera.any"
    android:required="true" />
<uses-feature
    android:name="android.hardware.camera.autofocus"
    android:required="false" />

现在我们有一种非常有序的权限处理方式。这里是步骤。我已经在这里添加了 Kotlin 的内容。

第 1 步。将此声明为全局变量或任何位置。

private val permissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { granted ->
        granted.entries.forEach {
            when (it.value) {
                true -> {
                    // Call whatever you want to do when someone allow the permission. 
                }
                false -> {
                    showPermissionSettingsAlert(requireContext())
                }
            }
        }
    }

步骤 2。

// You can put this line in constant.
val storagePermission = arrayOf(
    Manifest.permission.READ_EXTERNAL_STORAGE
)

// You can put this in AppUtil. 
fun checkPermissionStorage(context: Context): Boolean {
        val result =
            ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE)

        return result == PackageManager.PERMISSION_GRANTED
 }


// Put this where you need Permission check. 

    if (!checkPermissionStorage(requireContext())) {
        permissions.launch(
                storagePermission
        )
    } else {
        // Permission is already added. 
    }

步骤三:权限拒绝对话框。如果您愿意,可以使用此功能。

fun showPermissionSettingsAlert(context: Context) {
    val builder = AlertDialog.Builder(context)
    builder.setTitle("Grant Permission")
    builder.setMessage("You have rejected the Storage permission for the application. As it is absolutely necessary for the app to perform you need to enable it in the settings of your device. Please select \"Go to settings\" to go to application settings in your device.")
    builder.setPositiveButton("Allow") { dialog, which ->
        val intent = Intent()
        intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
        val uri = Uri.fromParts("package", context.packageName, null)
        intent.data = uri
        context.startActivity(intent)
    }
    builder.setNeutralButton("Deny") { dialog, which ->

        dialog.dismiss()
    }
    val dialog = builder.create()
    dialog.show()
}

谢谢你。

希望这能帮到你(Y)。


调用相机的代码不在主活动中,我是否仍应将方法放在主活动中? - David Faizulaev
是的,您可以在第一个活动中调用此权限。 - Saveen
尝试过了,没有帮助。 - David Faizulaev
你能否尝试一下这个:https://dev59.com/H4Tba4cB1Zd3GeqP30l7#26480984 - Saveen
仍然出现异常。 - David Faizulaev
显示剩余3条评论

24

这是我解决自己问题的方法:

首先,我认为当你在(SDK < 26)没有完整权限时尝试使用设备相机时会出现问题。

是的,即使你已经包含了此权限:

<uses-permission android:name="android.permission.CAMERA"/>
为解决此问题,我将 那个 改为了 这个
<uses-permission android:name="android.permission.CAMERA" 
                 android:required="true" 
                 android:requiredFeature="true"/>

这个来自 Android 文档的信息可能会非常有帮助

如果您的应用程序使用相机但不需要相机才能正常运行,可以将 android:required 设置为 false。这样做,Google Play 将允许没有相机的设备下载您的应用程序。然后,您需要在运行时调用 hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) 检查相机的可用性。如果没有可用的相机,则应禁用相机功能。


15

我的问题与模拟器权限有关,

解决方法如下:

1- 进入您的模拟器设置

2- 找到应用和通知

3- 点击添加权限

请参考图片:https://istack.dev59.com/z4GfK.webp

4- 从列表中选择相机

5- 在提供的列表中查找您的应用程序。

6- 启用相机

请参考图片:https://istack.dev59.com/dJ8wG.webpEnjoy

现在您可以在模拟器上使用相机:)


对我有用 :) - paulsm4

9
private String [] permissions = {"android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.ACCESS_FINE_LOCATION", "android.permission.READ_PHONE_STATE", "android.permission.SYSTEM_ALERT_WINDOW","android.permission.CAMERA"};

在你的OnCreate中添加以下内容:
int requestCode = 200;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    requestPermissions(permissions, requestCode);
}

1
这是最新的答案,适用于 v6(棉花糖版)上的“危险权限”发布。 - Dan Anderson

3

正如一些人所指出的那样,一个解决方案是从 AndroidManifest.xml 中删除相机权限,即删除这一行:

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

然而,对我来说这还不够,因为我的应用程序需要相机权限进行其他操作。所以对我有用的是将该权限标记为不必要,像这样:

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

它不起作用,但似乎像往常一样请求权限可以解决问题。 - Диана Ганеева

2
我有点晚了,但请检查一下,因为总会有一些更新。
根据官方开发者页面 - https://developer.android.com/training/camera/photobasics,你不需要在Manifest.xml中使用uses-permission,而是使用uses-feature
<uses-feature
    android:name="android.hardware.camera"
    android:required="false" />

注意 - 它是uses-feature,而不是uses-permission

请仔细检查,如果您同时使用uses-permissionuses-feature,可能会导致您的应用程序崩溃(这个注意事项比官方页面上的更新内容更重要,因为我同时使用了这两个参数,并且遇到了这个崩溃问题,当我开始处理我的应用程序中的相机模块时,我不知道为什么没有遇到此问题,但现在应用程序突然开始崩溃)

有关android:required的更多信息,请参考开发者页面:

如果您的应用程序使用相机功能,但不需要相机才能正常运行,请将android:required设置为false。这样做,Google Play允许没有相机的设备下载您的应用程序。然后,您需要在运行时通过调用hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)来检查相机的可用性。如果没有可用的相机,您应该禁用相机功能。


2

简短回答...... 当应用程序寻找权限时,如果没有权限就会抛出异常; 此外,在该情况下,它正在寻找两个权限,即首选存储和其次相机。

长篇回答...... 要让其在所有Android版本上正常工作,需要为它提供正确的权限。我正在循环获取两个权限:存储和相机,以便可以使用Intent。

  1. 在AndroidManifest.xml中保留权限声明
<uses-feature
        android:name="android.hardware.camera.any"
        android:required="true" />
    <uses-feature
        android:name="android.hardware.camera.autofocus"
        android:required="false" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  1. 通过以下方式检查或请求权限:
  private void myStoragePermission() {
        if (ContextCompat.checkSelfPermission(Activity_Scan_QR.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            myCameraPermission();
        } else {
            //changed here
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION);
            }
        }
    }

    //+10 changed its sinature as Fragment; without it  onRequestPermissionsResult won't bbe called
    private void myCameraPermission() {
        if (ContextCompat.checkSelfPermission(Activity_Scan_QR.this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            takePicture();
        } else {
            //changed here
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
            }
        }
    }

  1. 添加onRequestPermissionsResult方法
 @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_WRITE_PERMISSION:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    myStoragePermission();
                } else {

                    showSnackbar(R.string.act_ScanQR_txt13, R.string.settings,
                            new View.OnClickListener() {
                                @Override
                                public void onClick(View view) {
                                    // Build intent that displays the App settings screen.
                                    Intent intent = new Intent();
                                    intent.setAction(
                                            Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                    Uri uri = Uri.fromParts("package",
                                            BuildConfig.APPLICATION_ID, null);
                                    intent.setData(uri);
                                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                    startActivity(intent);
                                }
                            });
                }
            case REQUEST_CAMERA_PERMISSION:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    takePicture();
                } else {

                    showSnackbar(R.string.act_ScanQR_txt14, R.string.settings,
                            new View.OnClickListener() {
                                @Override
                                public void onClick(View view) {
                                    // Build intent that displays the App settings screen.
                                    Intent intent = new Intent();
                                    intent.setAction(
                                            Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                    Uri uri = Uri.fromParts("package",
                                            BuildConfig.APPLICATION_ID, null);
                                    intent.setData(uri);
                                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                    startActivity(intent);
                                }
                            });

                }
        }
    }


在上面的代码中,takePicture(); 是我调用意图(启动意图)的地方,在获取存储和相机权限后。

不要被错误信息搞糊涂了 ;)


0

如果您需要保留

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

在清单文件中添加相应的权限,确保在打开系统相机之前已经授予该权限。 在现代 Android 中,您可以像这样实现:

   val cameraPermissionResult =
    registerForActivityResult(ActivityResultContracts.RequestPermission()) { permitted ->
        if (permitted) {
            openSystemCamera()
        }
    }

你可以按照以下方式使用cameraPermissionResult:
cameraPermissionResult.launch(Manifest.permission.CAMERA)

如果您的应用程序已经被授予了该权限,它将只需调用openSystemCamera()而无需任何用户操作。 否则,将显示权限对话框,并根据用户选择打开系统相机。

0
如果其他人遇到了这个问题,我的问题是应用程序在运行时没有请求任何权限。小米设备似乎会自动拒绝通过adb安装的应用程序的权限请求。我只需通过设置启用权限即可解决问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接