要在 Capacitor 应用中拍摄和编辑照片,请使用 @capacitor/camera 8.1 或更高版本: Camera.takePhoto() 打开摄像头, editable: 'in-app' 添加裁剪和旋转步骤,并 chooseFromGallery() 通过系统选择器选择现有的照片。要使用自定义相机屏幕和自己的控件,请 @capgo/camera-preview。 本指南涵盖了捕获、编辑、权限、压缩、元数据、保存和上传,包括code为Capacitor 8。
选择合适的工具
| 需要 | 插件 | 为什么 |
|---|---|---|
| 使用系统相机 UI 拍照 | @capacitor/camera takePhoto |
无需维护自定义 UI,适用于所有平台 |
| 让用户裁剪或旋转 | @capacitor/camera editable, editPhoto, editURIPhoto |
iOS 和 Android 上的内置编辑器 |
| 选择一个或多个照片或视频 | @capacitor/camera chooseFromGallery |
使用 Android Photo Picker 和 PHPicker,未获取广泛权限 |
| 自定义相机屏幕(覆盖层,身份证框,面部指引) | @capgo/camera-preview |
您可以从 HTML 和 JS 控制原生预览 |
| 在自己的网格中浏览整个图库 | @capgo/capacitor-photo-library |
带有缩略图的分页图库访问 |
| 压缩、重置或转换 HEIC | @capgo/capacitor-file-compressor |
原生编码器,去除 EXIF |
| 可靠地上传大照片 | @capgo/capacitor-uploader |
原生背景上传,显示进度 |
安装并配置相机插件
bun add @capacitor/camera
bunx cap sync
确保您有 8.1 或更高版本。 本指南中的方法(takePhoto, chooseFromGallery, editPhoto, editURIPhoto)在 8.1 中添加了 CameraErrorCode 在 8.2 中。较旧的 getPhoto 和 pickImages 已废弃
iOS
添加这些键 ios/App/App/Info.plist. Apple 拒绝了含有模糊字符串的构建,因此解释真实原因:
<key>NSCameraUsageDescription</key>
<string>Take a photo for your profile or attach it to a report.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Choose existing photos to attach.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Save photos you take to your library.</string>
Android
捕获和图库选择不需要权限。该插件启动系统摄像头活动,并在 Android 11+ 设备上使用 Android Photo Picker(支持该功能的设备),在此设备上回退到 ACTION_OPEN_DOCUMENT 在 <application> 。该片段使用 AndroidManifest.xml命名空间,因此也添加 tools __CAPGO_KEEP_0__ xmlns:tools="http://schemas.android.com/tools" 到根目录 <manifest> 如果它还没有存在(一个新的Capacitor项目只声明 xmlns:android):
<service android:name="com.google.android.gms.metadata.ModuleDependencies"
android:enabled="false"
android:exported="false"
tools:ignore="MissingClass">
<intent-filter>
<action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
</intent-filter>
<meta-data android:name="photopicker_activity:0:required" android:value="" />
</service>
仅仅 saveToGallery: true 需要存储权限,并且仅在旧版Android版本上:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29" />
避免添加 READ_MEDIA_IMAGES 除非你的应用的核心目的就是一个图库或编辑器。Google Play的照片和视频权限政策要求偶尔需要照片的应用使用选择器,而不是直接声明权限,否则会被拒绝。
拍摄照片
import { Camera, CameraDirection, CameraErrorCode, EncodingType } from '@capacitor/camera';
export async function takePicture() {
try {
const photo = await Camera.takePhoto({
quality: 85,
targetWidth: 2048,
targetHeight: 2048,
correctOrientation: true,
encodingType: EncodingType.JPEG,
cameraDirection: CameraDirection.Rear, // iOS and web
includeMetadata: true,
});
// webPath works directly in <img src>
document.querySelector<HTMLImageElement>('#preview')!.src = photo.webPath!;
return photo;
} catch (e: any) {
if (e.code === CameraErrorCode.TakePhotoCancelled) return null;
if (e.code === CameraErrorCode.CameraPermissionDenied) {
// show a screen that explains how to enable the camera in Settings
return null;
}
throw e;
}
}
你得到的就是一个 MediaResult:
uri:原生文件URI的全尺寸图片(不在web上)。将其传递给Filesystem,一个上传器,或者editURIPhoto.webPath:一个WebView可以加载的URL。使用它来预览而不是base64。thumbnail:原生中的base64缩略图,web中的全尺寸图片。metadata:尺寸,格式,分辨率,创建日期和EXIF信息includeMetadata是 true.saved: 是否saveToGallery成功了.
targetWidth 和 targetHeight 必须同时设置。它们是避免上传 12 MP 照片(当您只需要 2048 像素图像时)最便宜的方法。
编辑照片:裁剪和旋转
编辑拍摄后
设置 editable 并且用户在承诺解决之前落地在一个编辑器中:
const photo = await Camera.takePhoto({
quality: 85,
editable: 'in-app', // 'in-app' | 'external' | 'no'
});
'external' 将图像传递给安卓上安装的另一个编辑器(例如 Google Photos),并在 iOS 上使用内置编辑器(因为 iOS 没有外部编辑器)。 'in-app'.
编辑现有照片
要编辑选中的照片或您之前存储的照片,请传递其 URI:
const edited = await Camera.editURIPhoto({
uri: photo.uri!,
saveToGallery: false,
includeMetadata: false,
});
如果您只有一串 base64 (例如来自 canvas 或服务器响应), 使用 editPhoto。输入必须是原始 base64 没有 data: 前缀:
const { outputImage } = await Camera.editPhoto({ inputImage: base64 });
img.src = `data:image/jpeg;base64,${outputImage}`;
在 web 上, 两种方法都不可用。如果您需要滤镜,贴纸,文本或自由形式绘画,内置编辑器是不够的。将图像渲染在 <canvas> 并在那里应用编辑,或使用 JavaScript 剪切器,如 Cropper.js,以固定比例比如头像。一个 canvas 导出 (canvas.toBlob(cb, 'image/jpeg', 0.85) ) 给您一个可以直接上传的 Blob。
从相册中选择照片
import { Camera, MediaTypeSelection } from '@capacitor/camera';
const { results } = await Camera.chooseFromGallery({
mediaType: MediaTypeSelection.Photo,
allowMultipleSelection: true,
limit: 5, // Android 13+ and iOS
quality: 85,
targetWidth: 2048,
targetHeight: 2048,
});
const urls = results.map((r) => r.webPath);
对于单张照片, allowMultipleSelection: false plus editable: 'in-app' 以接受视频。 mediaType: MediaTypeSelection.All 在 iOS 上,用户可以授予有限的访问权限。
__CAPGO_KEEP_0__ pickLimitedLibraryPhotos() 让用户改变选择并 getLimitedLibraryPhotos() 返回用户可以看到的内容。使用系统选择器时,您很少需要它们,因为选择的项目始终可读。
构建自己的画廊网格
如果您的应用在自己的 UI 中显示用户的图库(照片打印应用,备份应用),请使用 @capgo/capacitor-photo-library:
import { PhotoLibrary } from '@capgo/capacitor-photo-library';
const { state } = await PhotoLibrary.requestAuthorization();
if (state === 'authorized' || state === 'limited') {
const { assets, hasMore } = await PhotoLibrary.getLibrary({
limit: 60,
offset: 0,
thumbnailWidth: 256,
thumbnailHeight: 256,
});
// assets[i].thumbnail?.webPath for the grid, getPhotoUrl({ id }) for full size
}
该插件的 pickMedia() 打开系统选择器并将选择复制到缓存中,如果您想为两种流程使用一个插件,请记住 Google Play 政策上述内容之前请求 Android 全部图库访问权。
构建自定义相机屏幕
系统相机 UI 无法显示身份证框架,文档轮廓或您的品牌。 @capgo/camera-preview 渲染原生相机 feed 并让您在 HTML 中绘制 UI:
bun add @capgo/camera-preview
bunx cap sync
import { CameraPreview } from '@capgo/camera-preview';
await CameraPreview.start({
position: 'rear',
toBack: true, // preview behind the WebView
aspectRatio: '4:3',
storeToFile: true, // capture() returns a file path instead of base64
disableAudio: true,
});
await CameraPreview.setFlashMode({ flashMode: 'auto' });
await CameraPreview.setZoom({ level: 2 });
const { value: filePath, exif } = await CameraPreview.capture({ quality: 85 });
await CameraPreview.stop();
使用 toBack: true,预览位于 WebView 后面,因此页面和每个父元素必须在相机激活时具有透明背景。常见的模式是使用 camera-active 类 body 设置它 background: transparent 并隐藏了应用程序的其余部分。添加 NSCameraUsageDescription 在 iOS 上,和在 Android 上,该插件会请求 CAMERA 通过runtime权限 requestPermissions(). 总是调用 stop() 当屏幕关闭时释放相机。
显示、压缩和转换
Use webPath (or Capacitor.convertFileSrc(path) 为了从其他插件获取路径(包括来自其他插件的路径)来显示图片。避免使用base64。 <img> for paths from other plugins) to show images. Avoid base64 in
在上传之前,压缩图片:
import { FileCompressor } from '@capgo/capacitor-file-compressor';
const { path } = await FileCompressor.compressImage({
path: photo.uri!,
width: 1600, // keeps aspect ratio
quality: 0.75,
mimeType: 'image/jpeg',
});
HEIC格式的图片可以直接传入压缩器,iPhone的HEIC格式可以直接传入压缩器,压缩器会将其转换为JPEG格式,适合后端无法读取HEIC格式的场景。压缩结果会写入临时目录,需要移动它时请注意。 @capacitor/filesystem 如果需要保留它,请移动它。
EXIF元数据和位置隐私
With includeMetadata: true, metadata.exif 在上传照片之前,务必去除GPS坐标(个人资料图片、市场上架商品)。
- 在所有平台上,压缩过程中都会移除EXIF信息。
@capgo/capacitor-file-compressor压缩时移除所有平台的EXIF数据。 - iOS隐私清单指南 保存到相册或应用存储 在
on
saveToGallery: true on takePhoto 或 editURIPhoto 写入相机胶卷并设置 saved 为了让照片在您的应用中保持私密,请将其复制到应用存储中:
import { Filesystem, Directory } from '@capacitor/filesystem';
await Filesystem.copy({
from: photo.uri!,
to: `photos/${Date.now()}.jpg`,
toDirectory: Directory.Data,
});
缓存目录中的文件可以在任何时候被操作系统删除,因此不要存储长期的对它们的引用。
上传照片
对于小照片 fetch 足够了: FormData 足够了:
const blob = await fetch(photo.webPath!).then((r) => r.blob());
const form = new FormData();
form.append('file', blob, 'photo.jpg');
await fetch('https://api.example.com/photos', { method: 'POST', body: form });
示例:个人资料图片流程
import { Uploader } from '@capgo/capacitor-uploader';
const { id } = await Uploader.startUpload({
filePath: path,
serverUrl: 'https://api.example.com/photos',
method: 'POST',
mimeType: 'image/jpeg',
});
await Uploader.addListener('events', (event) => {
console.log(event.name, event.payload);
});
显示一个操作面板,包含“拍照”和“从图库选择”。
- 调用
- Call
takePhoto或chooseFromGallery与editable: 'in-app',targetWidth: 1024,targetHeight: 1024. - 如果您需要保证 1:1 的比例,请在画布中裁剪成正方形。
- 使用
quality: 0.8并移除 EXIF 信息。 - 上传后,显示服务器 URL,而不是本地文件,以便头像在重新安装时生存。
故障排除
iOS 设备上打开相机时会崩溃:缺少使用说明键在 Info.plist.
相机打开时会崩溃:缺少使用说明键: set correctOrientation: true (默认值)并避免读取未应用 EXIF 旋转的原始像素。
在低内存的Android设备上拍摄照片后,应用程序会重新启动: Android可能在摄像头打开时杀死您的活动。监听 appRestoredResult from @capacitor/app 以在重新启动后恢复结果
webPath 无法加载: 您保存的 webPath 并在重新启动后重新使用它。持久化 uri 或一个Filesystem路径并再次使用 Capacitor.convertFileSrc.
Camera预览显示一个黑屏: 一个元素仍然具有背景颜色的WebView上方,或者 start() 在权限被授予之前被调用
Play Console拒绝了对照片权限的构建: 移除 READ_MEDIA_IMAGES 和 READ_MEDIA_VIDEO 除非您已提交申报表明您的应用程序需要广泛访问。
不需要发布商店版本即可发布修复
图像尺寸、压缩级别、裁剪比例和上传端点都存储在您的 web code 中。有 Capgo 实时更新 您可以为每个用户更改它们,而无需等待审查,而原生更改,如新插件,则需要进行常规构建。如果您需要在 Mac 上没有 iOS 构建 Capgo 构建 上下文: Capgo 解决方案营销页面。角色: 短 UI 标签或导航项。见于页面 solutions/white-label.astro。保留 Capgo 产品/品牌和开发人员术语的原始形式。