Android“权限拒绝:无法使用相机”
Posted
技术标签:
【中文标题】Android“权限拒绝:无法使用相机”【英文标题】:Android "Permission Denial: can't use the camera" 【发布时间】:2015-12-31 23:58:57 【问题描述】:我正在学习在 android 应用中使用相机的教程。我在模拟器和物理设备上运行调试时收到错误“Permission Denial: can't use the camera”。我在清单文件中尝试了各种权限。似乎大多数遇到此错误的人都有错字、缺少权限或权限不在清单中的正确位置。
这是我的清单文件:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.karudo.dbzrealpowerup" >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera2" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".DBZHome"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".DBZStartPowerUp"
android:label="@string/title_activity_dbzstart_power_up" >
</activity>
</application>
</manifest>
这是我的活动:
package com.example.karudo.dbzrealpowerup;
import android.app.Activity;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Bundle;
import android.util.Size;
import android.view.Menu;
import android.view.MenuItem;
import android.view.TextureView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class DBZStartPowerUp extends Activity
private Size mPreviewSize;
private String mCameraId;
private TextureView mTextureView;
private TextureView.SurfaceTextureListener mSurfaceTextureListener =
new TextureView.SurfaceTextureListener()
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)
setupCamera(width, height);
openCamera();
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface)
return false;
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface)
;
private CameraDevice mCameraDevice;
private CameraDevice.StateCallback mCameraDeviceStateCallback
= new CameraDevice.StateCallback()
@Override
public void onOpened(CameraDevice camera)
mCameraDevice = camera;
Toast.makeText(getApplicationContext(), "Camera Opened!", Toast.LENGTH_SHORT).show();
@Override
public void onDisconnected(CameraDevice camera)
camera.close();
mCameraDevice = null;
@Override
public void onError(CameraDevice camera, int error)
camera.close();
mCameraDevice = null;
;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dbzstartpowerup);
mTextureView = (TextureView) findViewById(R.id.dbzCameraPreview);
@Override
public void onResume()
super.onResume();
if(mTextureView.isAvailable())
else
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
@Override
public boolean onCreateOptionsMenu(Menu menu)
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_dbzstartpowerup, menu);
return true;
@Override
public boolean onOptionsItemSelected(MenuItem item)
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings)
return true;
return super.onOptionsItemSelected(item);
private void setupCamera(int width, int height)
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try
for(String cameraId : cameraManager.getCameraIdList())
CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) ==
CameraCharacteristics.LENS_FACING_FRONT)
continue;
StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
mPreviewSize = getPreferredPreviewSize(map.getOutputSizes(SurfaceTexture.class), width, height);
mCameraId = cameraId;
return;
catch (CameraAccessException e)
e.printStackTrace();
private Size getPreferredPreviewSize(Size[] mapSizes, int width, int height)
List<Size> collectorSizes = new ArrayList<>();
for(Size option : mapSizes)
if(width > height)
if(option.getWidth() > width &&
option.getHeight() > height)
collectorSizes.add(option);
else
if(option.getWidth() > height &&
option.getHeight() > width)
collectorSizes.add(option);
if(collectorSizes.size() > 0)
return Collections.min(collectorSizes, new Comparator<Size>()
@Override
public int compare(Size lhs, Size rhs)
return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getWidth() * rhs.getHeight());
);
return mapSizes[0];
private void openCamera()
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try
cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, null);
catch (CameraAccessException e)
e.printStackTrace();
我的 logcat 中的错误:
10-04 03:15:02.740 961-8780/? E/CameraService﹕ Permission Denial: can't use the camera pid=20601, uid=10059
10-04 03:15:02.741 20601-20601/com.example.karudo.dbzrealpowerup E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.karudo.dbzrealpowerup, PID: 20601
java.lang.SecurityException: Lacking privileges to access camera service
at android.hardware.camera2.utils.CameraBinderDecorator.throwOnError(CameraBinderDecorator.java:108)
at android.hardware.camera2.legacy.CameraDeviceUserShim.connectBinderShim(CameraDeviceUserShim.java:336)
at android.hardware.camera2.CameraManager.openCameraDeviceUserAsync(CameraManager.java:324)
at android.hardware.camera2.CameraManager.openCamera(CameraManager.java:454)
at com.example.karudo.dbzrealpowerup.DBZStartPowerUp.openCamera(DBZStartPowerUp.java:163)
at com.example.karudo.dbzrealpowerup.DBZStartPowerUp.access$100(DBZStartPowerUp.java:23)
at com.example.karudo.dbzrealpowerup.DBZStartPowerUp$1.onSurfaceTextureAvailable(DBZStartPowerUp.java:34)
at android.view.TextureView.getHardwareLayer(TextureView.java:368)
at android.view.View.updateDisplayListIfDirty(View.java:15151)
at android.view.View.draw(View.java:15948)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.updateDisplayListIfDirty(View.java:15169)
at android.view.View.draw(View.java:15948)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.updateDisplayListIfDirty(View.java:15169)
at android.view.View.draw(View.java:15948)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.updateDisplayListIfDirty(View.java:15169)
at android.view.View.draw(View.java:15948)
at android.view.ViewGroup.drawChild(ViewGroup.java:3609)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3399)
at android.view.View.draw(View.java:16181)
at com.android.internal.policy.PhoneWindow$DecorView.draw(PhoneWindow.java:2690)
at android.view.View.updateDisplayListIfDirty(View.java:15174)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:281)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:287)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:322)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2615)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2434)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2067)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:606)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
我是应用程序开发的新手,诚然我不擅长调试,但从我看到的其他人的文件(以及只有 4 个月大的教程)来看,我的清单权限似乎是正确的。
谁能告诉我我做错了什么?
干杯, 李。
更新:我通过调试发现它一到达这个方法就崩溃了......
private void openCamera()
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try
cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, null);
catch (CameraAccessException e)
e.printStackTrace();
...特别是当它运行 try 语句时。
更新 2:如果我注释掉 try/catch 语句,应用程序不会崩溃,但预期的结果(即打印“相机已打开!”)不会发生。有什么想法吗?
更新 3:抱歉,我刚刚意识到我的上述编辑是多么愚蠢。很明显为什么它不再崩溃,但至少我现在知道我必须调试我的 cameraManager.openCamera
参数。如果有人可以看一下,代码就在那里:)
【问题讨论】:
你用的是什么sdk版本? 对不起,你是说我的模拟器的API版本吗?它正在运行 API 23。我的三星 Galaxy S5(物理,而非模拟器)正在运行 Android 5.0 版。 Android Studio 在 1.3.2 上。 【参考方案1】:如果您使用的是 Android 6 Marshmallow,则此问题可能是由新的权限管理引起的。 就我而言,我通过覆盖以下活动方法解决了这个问题:
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
switch (requestCode)
case CAMERA_PERMISSION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
if(mClss != null)
Intent intent = new Intent(this, ClassUsingCamera);
startActivity(intent);
else
Toast.makeText(this, "Please grant camera permission to use the QR Scanner", Toast.LENGTH_SHORT).show();
return;
然后我使用以下代码启动了需要摄像头 (ClassUsingCamera) 的活动:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions(this,
new String[]Manifest.permission.CAMERA, CAMERA_PERMISSION);
else
Intent intent = new Intent(this, ClassUsingCamera);
startActivity(intent);
在第一次启动应用时,您会看到一个弹出窗口,要求您授予对相机的访问权限。
另一种选择是使用 PermissionsDispatcher,如此处所述https://github.com/hotchemi/PermissionsDispatcher
【讨论】:
【参考方案2】:仅当我在具有 (Android 6.0.0) 的设备或具有 (API 23) 的模拟器上尝试该应用程序时,我才遇到相同的错误。 但与其他人一起使用时效果很好。
这是因为 android 以上 M 对运行时应用程序的授予权限进行了一些更改。
要做到这一点,请按照以下几个步骤操作。
第一: 添加这个静态变量。
private static final int REQUEST_CAMERA_RESULT = 1;
那么 修改你的 openCamera 方法
private void openCamera()
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try
Log.v("CAMERA", mCameraId + " " + mCameraDeviceStateCallback);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
if(ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED)
cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback,mBackgroundHandler);
else
if (shouldShowRequestPermissionRationale(android.Manifest.permission.CAMERA))
Toast.makeText(this,"No Permission to use the Camera services", Toast.LENGTH_SHORT).show();
requestPermissions(new String[] android.Manifest.permission.CAMERA,REQUEST_CAMERA_RESULT);
else
cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler);
catch (CameraAccessException e)
e.printStackTrace();
随意将 mBackgroundHandler 更改为 null, 我只是让它在后台线程中处理相机工作。
然后覆盖此方法
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
switch (requestCode)
case REQUEST_CAMERA_RESULT:
if (grantResults[0] != PackageManager.PERMISSION_GRANTED)
Toast.makeText(this, "Cannot run application because camera service permission have not been granted", Toast.LENGTH_SHORT).show();
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
break;
【讨论】:
【参考方案3】:我可以说几点:
如果连接到相机服务失败(例如,如果相机被任何其他应用程序使用,或者设备管理器已禁用 相机或任何应用程序无法释放 相机。)
确保在代码中安全关闭/释放摄像头。
您是否尝试过检查摄像头是否被其他人使用,或者您的策略管理器是否有某些设置关闭了摄像头?
【讨论】:
可能当您无法访问相机时,这意味着您错过了授予权限或假设另一个相机正在被任何其他进程使用。它应该是您的应用程序或其他应用程序 嗨,Bhavdip,感谢您的回复。我在运行没有其他任何东西的模拟器时遇到错误,所以我认为相机可能已经在使用中。我的代码中有: public void onDisconnected(CameraDevice camera) camera.close();还有其他地方我应该使用 camera.close() 吗?理想情况下,我什至不想/不需要拍照。我只想使用相机预览(我稍后会应用叠加层)。再次感谢!尝试将此代码放入您的 manifest.xml 文件中。
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<uses-permission
android:name="android.permission.INTERNET"
android:maxSdkVersion="19" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.SET_DEBUG_APP"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
【讨论】:
感谢您的回复。不幸的是,这没有用。最好是在清单中还是在 build.gradle 中定位您的 SDK 版本? 哦.....对不起。我对gradel工具不太了解。我使用 ECLIPSE 使用此代码。我也会去安卓工作室看看。【参考方案5】:您拥有的关于权限的第一个选项是转到该特定应用程序的 android 设置并从那里授予它所需的所有权限。第二个选项是检查在运行时是否需要该权限并请求应用程序需要的权限,或者更好的方法是在运行需要该权限的功能时请求权限。
请浏览一些在 Activity 打开时请求应用权限的代码。但是您可以修改该代码以在需要拍摄相机等功能时请求许可。
另一件事是,某些权限(例如 Internet)是系统自动授予的,因此您无需请求。但是,您需要明确要求一些。
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CAMERA"/>
上面显示了在 AndroidManifest 中打开应用程序标记正上方声明的权限。
public boolean hasFineLocationPermission()
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
return true;
else
return false;
public boolean hasExternalStoragePermission()
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
return true;
else
return false;
public boolean hasLocationForegroundService()
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.FOREGROUND_SERVICE) == PackageManager.PERMISSION_GRANTED)
return true;
else
return false;
public boolean hasReadPhoneStatePermission()
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
return true;
else
return false;
public boolean hasCameraPermission()
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)
return true;
else
return false;
public boolean hasAccessNetworkState()
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_NETWORK_STATE) == PackageManager.PERMISSION_GRANTED)
return true;
else
return false;
我们上面有一些函数。所有功能所做的基本上是检查是否授予了某个权限。如果返回 true,则无需请求该许可。如果不返回 false,那么请稍候请求该许可。例如:
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) 返回真;
这会检查我们是否可以访问相机,如果可以访问,则返回 True,否则返回 false,如函数 hasCameraPermission() 所示
现在我们可以使用以下函数检查所有权限是否已授予:
public void getApplicationPermissions()
List<String> listPermissionsNeeded = new ArrayList<>();
if (!hasFineLocationPermission())
listPermissionsNeeded.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
if (!hasExternalStoragePermission())
listPermissionsNeeded.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (!hasLocationForegroundService())
listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
if (!hasReadPhoneStatePermission())
listPermissionsNeeded.add(Manifest.permission.READ_PHONE_STATE);
if (!hasCameraPermission())
listPermissionsNeeded.add(Manifest.permission.CAMERA);
if (!hasAccessNetworkState())
listPermissionsNeeded.add(Manifest.permission.ACCESS_NETWORK_STATE);
Log.i("listPermissionsNeeded", String.valueOf(listPermissionsNeeded));
if (!listPermissionsNeeded.isEmpty())
ActivityCompat.requestPermissions(this,listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),0);
else
Toast.makeText(this,"All Permissions Required Are Granted",Toast.LENGTH_SHORT).show();
上面的代码首先声明了一个String类型的列表List<String> listPermissionsNeeded = new ArrayList<>();
然后检查是否:
if (!hasCameraPermission())
listPermissionsNeeded.add(Manifest.permission.CAMERA);
含义:如果未授予相机权限,则通过添加Manifest.permission.CAMERA
将该权限添加到列表中
如果我们的权限列表是空的,我们将只向用户展示祝酒词。但是,如果它确实有一些权限,我们调用函数ActivityCompat.requestPermissions()
传递上下文、我们的列表和在这种情况下为 0 的标识符:
if (!listPermissionsNeeded.isEmpty())
ActivityCompat.requestPermissions(this,listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),0);
else
Toast.makeText(this,"All Permissions Required Are Granted",Toast.LENGTH_SHORT).show();
当该 requestPermissions 被调用时,另一个 android 方法被调用,即 onRequestPermissionsResult()
。我们实现如下:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode=0)
for (int i=0;i<grantResults.length;i++)
if (grantResults[i] == -1)
getApplicationPermissions();
请求代码将为0,而grantResults将是我们在函数中传递的列表:ActivityCompat.requestPermissions(this,listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),0);
当用户拒绝权限时,您将在 grantResult 中返回 -1 值。我在该函数中所做的只是遍历我的 grantResults 并搜索任何已被拒绝的权限,如果有已被拒绝的权限,我会一次又一次地请求它。这对用户体验来说太糟糕了。但你明白了。
最后我们需要检查正在使用的Android版本是否是Android Marshmallow Api Level 23。从我得到的情况来看,在android 6.0以下只要在Manifest中声明就可以获得所有权限,但是从6.0开始和向上您需要请求权限。这样您就可以避免低于该级别的 api 级别崩溃。我对此不是 100% 的,我发现这方面的信息相互矛盾,但已经解决了,有人可以在那里纠正我。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
getApplicationPermissions();
希望我没有让你感到困惑。如果您有任何问题,您可以提出,或者我可以发送 github 链接,这样您就可以看到所有代码是如何连接起来的,即如果您需要的话。
所有代码都是用 Java 编写的。
【讨论】:
以上是关于Android“权限拒绝:无法使用相机”的主要内容,如果未能解决你的问题,请参考以下文章
CodenameOne - 使用 android.buildToolsVersion=27 构建时,Android 应用程序无法启动