Camera权限与配置:AndroidManifest权限声明、动态权限申请、摄像头特性检测、Camera配置参数详解

好,我们正式开始聊摄像头开发的第一道坎——权限与配置。

说实话,很多新手一上来就急着写拍照逻辑,结果App一运行就闪退。为什么?权限没处理好。我当年也犯过这个错,在模拟器上跑得好好的,换到真机上直接崩溃。后来才发现,Android 6.0以后权限模型变了,光在Manifest里声明是不够的。

AndroidManifest权限声明

先说说最基础的。你要用摄像头,得先在AndroidManifest.xml里告诉系统:我要用这个硬件。

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

就这一行?嗯,基本是这样。但有个细节很多人忽略——如果你只是想让有摄像头的设备才能安装你的App,可以加个uses-feature标签:

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

设为true的话,没有摄像头的设备在Google Play上根本搜不到你的App。我个人习惯是设为false,然后在代码里动态检测。这样平板用户也能装,只是拍照功能不可用而已。

重要提醒:从Android 10(API 29)开始,如果你用Camera2 API,还需要声明android.permission.CAMERA。但如果你只是用系统相机Intent拍照,不需要这个权限——系统会帮你处理。

动态权限申请

好,Manifest写完了,你以为就完了?不,这只是第一步。

Android 6.0(API 23)引入了运行时权限模型。说白了,敏感权限不能只在安装时问一次,必须在运行时弹窗让用户确认。摄像头权限就是典型的敏感权限。

我见过太多人把权限申请写得特别复杂。其实核心就三步:

  1. 检查权限是否已授予——用ContextCompat.checkSelfPermission()
  2. 如果没有,发起请求——用ActivityCompat.requestPermissions()
  3. 处理回调结果——重写onRequestPermissionsResult()

看代码:

// 检查权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
        != PackageManager.PERMISSION_GRANTED) {
    // 权限未授予,发起请求
    ActivityCompat.requestPermissions(this,
            new String[]{Manifest.permission.CAMERA},
            CAMERA_PERMISSION_CODE);
} else {
    // 权限已授予,直接打开摄像头
    openCamera();
}

// 处理回调
@Override
public void onRequestPermissionsResult(int requestCode,
                                       @NonNull String[] permissions,
                                       @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == CAMERA_PERMISSION_CODE) {
        if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            openCamera();
        } else {
            // 用户拒绝了权限
            Toast.makeText(this, "需要摄像头权限才能拍照", Toast.LENGTH_SHORT).show();
        }
    }
}

小技巧:如果用户第一次拒绝,第二次再弹窗时可以加个解释。用shouldShowRequestPermissionRationale()判断是否需要向用户说明为什么需要这个权限。我曾经在一个项目中没加这个判断,用户连续拒绝两次后直接勾选了"不再询问",后面就再也弹不出权限申请了——只能让用户去设置里手动开启。

摄像头特性检测

你想想看,如果设备根本没有摄像头,你申请权限有什么用?所以,在申请权限之前,最好先检测一下设备是否真的有摄像头硬件。

为什么会有设备没有摄像头?嗯,Android设备种类太多了。有些平板、电视盒子、车载设备真的没有摄像头。我就在一个智能电视项目上踩过这个坑——代码里直接调了摄像头,结果在电视上崩溃了。

检测方法很简单:

PackageManager pm = getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
    // 有摄像头
} else {
    // 没有摄像头,隐藏拍照按钮
}

如果你想检测是否有前置摄像头:

if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
    // 有前置摄像头
}

还可以检测闪光灯:

if (pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
    // 有闪光灯
}

注意:hasSystemFeature()检查的是硬件特性,不是权限。即使你没有申请CAMERA权限,这个方法也能正常调用。所以它适合放在权限申请之前做预检。

Camera配置参数详解

好,权限有了,硬件也确认了,接下来就是配置摄像头了。这里我主要讲Camera1 API的参数配置,因为Camera2的配置更复杂,我们后面会单独讲。

Camera1 API的核心是Camera.Parameters类。拿到这个对象后,你可以做很多事:

Camera camera = Camera.open();
Camera.Parameters params = camera.getParameters();

// 设置预览尺寸
params.setPreviewSize(1280, 720);

// 设置拍照尺寸
params.setPictureSize(1920, 1080);

// 设置对焦模式
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);

// 设置白平衡
params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);

// 设置闪光灯模式
params.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);

camera.setParameters(params);

这里有几个关键参数,我挑重点说:

参数 说明 常用值
预览尺寸 取景器显示的尺寸,不是最终照片尺寸 1280x720, 1920x1080
拍照尺寸 最终照片的分辨率 1920x1080, 3264x2448
对焦模式 控制摄像头如何对焦 AUTO, CONTINUOUS_PICTURE, MACRO
白平衡 调整色温,让颜色更自然 AUTO, DAYLIGHT, CLOUDY, FLUORESCENT
闪光灯模式 控制闪光灯行为 AUTO, ON, OFF, TORCH

避坑指南:设置参数前,一定要先检查设备是否支持该参数。比如不是所有摄像头都支持CONTINUOUS_PICTURE对焦模式。我曾经在低端机上直接设置了这个模式,结果setParameters()抛了个异常。正确的做法是先用getSupportedFocusModes()获取支持的模式列表,再从中选择一个。

List<String> supportedFocusModes = params.getSupportedFocusModes();
if (supportedFocusModes != null
        && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
    params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (supportedFocusModes != null
        && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
    params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}

同样的逻辑也适用于预览尺寸和拍照尺寸。先获取支持列表,再选一个最合适的。我个人习惯是优先选16:9的比例,因为现在大部分屏幕都是16:9的,预览不会变形。

知识体系总览

说了这么多,我把这一章的核心逻辑画成了一张图,方便你理解整个流程:

Camera权限与配置 — 核心流程 1. Manifest声明 uses-permission CAMERA 2. 硬件检测 hasSystemFeature() 3. 动态权限申请 requestPermissions() 权限已授予? 提示用户 / 跳转设置 4. 配置参数 Camera.Parameters 关键参数 • 预览尺寸 (PreviewSize) • 拍照尺寸 (PictureSize) • 对焦模式 (FocusMode) • 白平衡 (WhiteBalance) 注意:每一步失败都应给出用户友好的提示,不要直接崩溃

这张图把整个流程串起来了。你从左上角开始,按箭头方向走,每一步都有对应的代码实现。记住,每一步都可能失败——Manifest没写、硬件不支持、用户拒绝权限、参数不兼容——所以每一步都要做异常处理。

嗯,这一章的内容就这些。权限和配置是摄像头开发的基础,基础打牢了,后面写拍照逻辑才不容易出问题。下一章我们开始写真正的拍照代码。


公众号:蓝海资料掘金营,微信deep3321