2. Camera权限与配置:AndroidManifest权限声明、运行时权限处理、Camera特性检测
做Android摄像头开发,第一步不是写代码,而是搞定权限。这事儿我踩过不少坑,今天跟你好好聊聊。
说白了,摄像头权限就两类:一个是声明我要用,一个是运行时问用户要。这两步缺一不可,顺序也不能搞错。
2.1 AndroidManifest中的权限声明
先打开你的 AndroidManifest.xml,在 <manifest> 标签里加上这几行:
<uses-permission android:name="android.permission.CAMERA" />
<!-- 如果你还需要录制视频 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- 存储权限,Android 10以下需要 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
嗯,这里要注意。从Android 6.0开始,CAMERA属于危险权限,光声明不够,还得运行时申请。但如果你不声明,运行时申请也不会弹窗——系统直接拒绝。
另外,如果你的应用必须依赖摄像头才能工作(比如扫码App),可以加个 uses-feature:
<uses-feature android:name="android.hardware.camera" android:required="true" />
这样Google Play会帮你过滤掉没有摄像头的设备。如果你的App没有摄像头也能用大部分功能,设成 false 就行。
2.2 运行时权限处理
声明完了,接下来就是运行时弹窗。我个人习惯把权限申请封装成一个工具类,这样每个页面调用起来都干净。
核心流程其实就三步:
- 检查权限:用
ContextCompat.checkSelfPermission() - 申请权限:用
ActivityCompat.requestPermissions() - 处理回调:重写
onRequestPermissionsResult()
看代码:
// 检查权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
// 没有权限,需要申请
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION);
} else {
// 已有权限,直接打开摄像头
openCamera();
}
回调处理:
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 用户同意了
openCamera();
} else {
// 用户拒绝了
showPermissionDeniedDialog();
}
}
}
shouldShowRequestPermissionRationale() 来判断是否被永久拒绝。
你想想看,用户拒绝一次后,第二次申请时弹个解释说明,成功率会高很多。我在项目里试过,从40%提升到了70%以上。
2.3 Camera特性检测
权限拿到了,但设备不一定支持你想要的特性。比如有些低端机没有前置摄像头,或者不支持你需要的分辨率。
检测摄像头数量:
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
String[] cameraIdList = manager.getCameraIdList();
// cameraIdList.length 就是摄像头数量
for (String id : cameraIdList) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
// 这是前置摄像头
}
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
检测是否支持闪光灯:
Boolean hasFlash = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
if (hasFlash != null && hasFlash) {
// 支持闪光灯
}
检测支持的分辨率:
StreamConfigurationMap configMap =
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (configMap != null) {
Size[] outputSizes = configMap.getOutputSizes(ImageFormat.JPEG);
// 遍历 outputSizes 找到你需要的分辨率
}
核心要点:不要假设所有设备都一样。我见过一台平板只有后置摄像头,也见过某款手机最大只支持 1920x1080 的预览。提前检测,提前适配,比用户反馈崩溃再修要好得多。
下面这张图总结了整个权限与配置的流程:
说实话,权限和配置这部分看起来简单,但实际项目中出问题最多的就是这里。我见过太多App因为权限没处理好,在用户手机上直接闪退。
最后给你几个实战建议:
- 权限申请时机:不要一启动就弹窗。等用户真正要用摄像头时再申请,成功率更高。
- 拒绝后的处理:不要直接退出App。给用户一个友好的提示,告诉他为什么需要这个权限。
- 特性检测要缓存:每次打开摄像头都查一遍特性有点浪费。我习惯在Application初始化时查一次,存到全局变量里。
- 兼容性测试:不同厂商对权限的处理有差异。比如某些国产ROM,即使你申请了权限,用户也可以在设置里单独关闭某个权限。
📌 我的经验:在项目的Application类里做一个统一的权限检测和特性缓存。这样所有页面都能复用,代码也干净。你想想看,如果每个Activity都写一遍检测逻辑,维护起来多痛苦。
好了,权限和配置就聊到这儿。记住这个流程:声明 → 申请 → 检测。每一步都做到位,摄像头这块的基础就打牢了。
公众号:蓝海资料掘金营,微信deep3321