@capacitor/camera
Camera API 提供使用相机拍照或从相册中选择已有照片的功能。
安装
npm install @capacitor/camera
npx cap sync
iOS 平台
iOS 需要在 Info.plist 中添加并填写以下使用说明:
NSCameraUsageDescription(隐私 - 相机使用说明)NSPhotoLibraryAddUsageDescription(隐私 - 相册添加使用说明)NSPhotoLibraryUsageDescription(隐私 - 相册使用说明)
阅读 iOS 指南 中的 配置 Info.plist 了解有关在 Xcode 中设置 iOS 权限的更多信息。
Android 平台
从设备相册选取现有图片时,现在使用 Android Photo Picker 组件。Photo Picker 可在满足以下条件的设备上使用:
- 运行 Android 11(API 级别 30)或更高版本
- 通过 Google 系统更新接收模块化系统组件变 更
较旧的设备和运行 Android 11 或 12 且支持 Google Play 服务的 Android Go 设备可以安装回溯移植版本的 photo picker。要启用通过 Google Play 服务自动安装回溯移植的 photo picker 模块,请在 AndroidManifest.xml 文件的 <application> 标签中添加以下条目:
<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>
如果不添加该条目,在不支持 Photo Picker 的设备上,Photo Picker 组件将回退到 Intent.ACTION_OPEN_DOCUMENT。
Camera 插件不需要权限,除非使用 saveToGallery: true,在这种情况下,应将以下权限添加到 AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
您也可以仅在需要这些权限的 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"/>
存储权限用于读取/保存照片文件。
阅读 Android 指南 中的 设置权限 了解有关设置 Android 权限的更多信息。
此外,由于 Camera API 会启动一个单独的 Activity 来处理拍照,您应该在 App 插件中监听 appRestoredResult,以处理在 Activity 运行时应用被操作系统终止时可能发送的相机数据。
变量
此插件将使用以下项目变量(在应用的 variables.gradle 文件中定义):
androidxExifInterfaceVersion:androidx.exifinterface:exifinterface的版本(默认值:1.4.1)androidxMaterialVersion:com.google.android.material:material的版本(默认值:1.13.0)
PWA 注意事项
在 Web 上,takePhoto 可以使用 PWA Elements 的 pwa-camera-modal 自定义元素提供类似原生的相机 UI。如果未注册该元素,插件将回退到 <input type="file"> 选择器。无论是否安装了 PWA Elements,chooseFromGallery 在 Web 上始终使用 <input type="file">。
以编程方式安装 PWA Elements
有关完整说明,请参阅 PWA Elements 安装指南。
提供自定义相机元素
您无需使用 @ionic/pwa-elements,而是可以注册自己的 pwa-camera-modal 自定义元素。插件通过以下接口与其交互:
| 成员 | 类型 | 描述 |
|---|---|---|
facingMode | string 属性 | 在显示前设置为 'user'(前置摄像头)或 'environment'(后置摄像头) |
componentOnReady() | 方法 → Promise<void> | 插件创建元素后调用 ;当元素就绪时 resolve |
present() | 方法 | 由插件调用以显示相机 UI |
dismiss() | 方法 | 由插件调用以在拍照或取消后关闭相机 UI |
onPhoto | 事件 | 当用户拍照或取消时触发。event.detail 必须是 Blob(已拍照)、null(用户取消)或 Error(出现问题) |
class MyCameraModal extends HTMLElement {
facingMode = 'environment';
componentOnReady() {
return Promise.resolve();
}
present() {
// 显示您的自定义相机 UI,完成后只触发一次 'onPhoto' 事件:
// - Blob:用户拍照
// - null:用户取消
// - Error:出现问题
// 示例:
this.dispatchEvent(new CustomEvent('onPhoto', { detail: photoBlob }));
}
dismiss() {
// 隐藏您的自定义相机 UI(插件在接收到 'onPhoto' 后调用)
}
}
customElements.define('pwa-camera-modal', MyCameraModal);
示例
拍照
import { Camera } from '@capacitor/camera';
const takePicture = async () => {
try {
const result = await Camera.takePhoto({
quality: 90,
includeMetadata: true,
});
// result.webPath 可以直接设置为图片元素的 src
imageElement.src = result.webPath;
// 在原生平台:将 result.uri 传递给 Filesystem API 获取全分辨率 base64,
// 或使用 result.thumbnail 获取较低分辨率的 base64 预览。
// 在 Web 上:result.thumbnail 包含完整的 base64 编码图片。
console.log('Format:', result.metadata?.format);
console.log('Resolution:', result.metadata?.resolution);
} catch (e) {
const error = e as any;
// error.code 包含结构化的错误代码(例如 'OS-PLUG-CAMR-0003')
// 当从原生层抛出时。有关所有代码,请参阅错误部分。
const message = error.code ? `[${error.code}] ${error.message}` : error.message;
console.error('takePhoto failed:', message);
}
};
从相册选择
import { Camera, MediaTypeSelection } from '@capacitor/camera';
const pickMedia = async () => {
try {
const { results } = await Camera.chooseFromGallery({
mediaType: MediaTypeSelection.All, // 照片、视频或两者
allowMultipleSelection: true,
limit: 5,
includeMetadata: true,
});
for (const item of results) {
console.log('Type:', item.type); // MediaType.Photo 或 MediaType.Video
console.log('webPath:', item.webPath);
console.log('Format:', item.metadata?.format);
console.log('Size:', item.metadata?.size);
}
} catch (e) {
const error = e as any;
const message = error.code ? `[${error.code}] ${error.message}` : error.message;
console.error('chooseFromGallery failed:', message);
}
};
录制和播放视频
import { Camera } from '@capacitor/camera';
const recordAndPlay = async () => {
let videoUri: string | undefined;
try {
const result = await Camera.recordVideo({
saveToGallery: false,
isPersistent: true, // 保持文件在应用启动间可用
includeMetadata: true,
});
videoUri = result.uri;
console.log('Duration:', result.metadata?.duration);
console.log('Saved to gallery:', result.saved);
} catch (e) {
const error = e as any;
const message = error.code ? `[${error.code}] ${error.message}` : error.message;
console.error('recordVideo failed:', message);
return;
}
if (videoUri) {
try {
await Camera.playVideo({ uri: videoUri });
} catch (e) {
const error = e as any;
const message = error.code ? `[${error.code}] ${error.message}` : error.message;
console.error('playVideo failed:', message);
}
}
};
从 base64 字符串编辑照片
editPhoto 从 base64 编码的图片打开应用内编辑器,并在 outputImage 中返回编辑后的图片作为 base64 字符串。
import { Camera } from '@capacitor/camera';
const editFromBase64 = async (base64Image: string) => {
try {
const { outputImage } = await Camera.editPhoto({
inputImage: base64Image, // 原始 base64,无 data URL 前缀
});
// outputImage 是编辑后的图片,base64 编码
imageElement.src = `data:image/jpeg;base64,${outputImage}`;
} catch (e) {
const error = e as any;
const message = error.code ? `[${error.code}] ${error.message}` : error.message;
console.error('editPhoto failed:', message);
}
};
从 URI 编辑照片
editURIPhoto 从文件 URI(例如从 takePhoto 或 Filesystem API 获取)打开应用内编辑器,并返回 MediaResult。
import { Camera } from '@capacitor/camera';
const editFromURI = async (uri: string) => {
try {
const result = await Camera.editURIPhoto({
uri,
saveToGallery: false,
includeMetadata: true,
});
// result.webPath 可以直接用作图片的 src
imageElement.src = result.webPath;
console.log('Format:', result.metadata?.format);
console.log('Size:', result.metadata?.size);
console.log('Saved to gallery:', result.saved);
} catch (e) {
const error = e as any;
const message = error.code ? `[${error.code}] ${error.message}` : error.message;
console.error('editURIPhoto failed:', message);
}
};
迁移到新 API
版本 8.1.0 引入了新的改进 API,并弃用了 getPhoto 和 pickImages。
替换 getPhoto
getPhoto 通过 CameraSource 处理三种来源:Camera、Photos 和 Prompt。Camera 和 Photos 现在映射到不同的方法,而 Prompt 已被移除。
CameraSource.Camera 改为 takePhoto
新 API 不支持 CameraResultType.Base64 和 CameraResultType.DataUrl。请参阅 结果类型变更 了解替代方案。
// 之前
const photo = await Camera.getPhoto({
source: CameraSource.Camera,
quality: 90,
allowEditing: true,
resultType: CameraResultType.Uri,
direction: CameraDirection.Rear,
width: 1280,
height: 720,
});
const imageUrl = photo.webPath;
// 之后
const result = await Camera.takePhoto({
quality: 90,
editable: 'in-app', // 替换 allowEditing: true
cameraDirection: CameraDirection.Rear, // 替换 direction
targetWidth: 1280, // 替换 width (1)
targetHeight: 720, // 替换 height (1)
});
const imageUrl = result.webPath;
(1) width/height 各自独立工作,在保持宽高比的同时设置最大尺寸。targetWidth/targetHeight 必须一起使用——仅设置一个无效。
CameraSource.Photos 改为 chooseFromGallery
// 之前
const photo = await Camera.getPhoto({
source: CameraSource.Photos,
quality: 90,
resultType: CameraResultType.Uri,
});
const imageUrl = photo.webPath;
// 之后
const { results } = await Camera.chooseFromGallery({
quality: 90,
});
const imageUrl = results[0].webPath;
CameraSource.Prompt(或默认)
getPhoto 之前显示一个原生提示,让用户在相机和相册之间选择。此提示不再属于插件的一部分。您应使用自己的 UI(例如使用 @capacitor/action-sheet)构建提示,然后根据用户的选择调用 takePhoto 或 chooseFromGallery。
// 之前
const photo = await Camera.getPhoto({
// source 默认为 CameraSource.Prompt
quality: 90,
resultType: CameraResultType.Uri,
});
// 之后:显示您自己的 UI 来确定来源,然后调用相应的方法
const result = await Camera.takePhoto({ quality: 90 });
// 或
const { results } = await Camera.chooseFromGallery({ quality: 90 });
结果类型变更
getPhoto 返回一个 Photo 对象,其中可用字段取决于 resultType。新 API 完全移除了 resultType——MediaResult 具有固定的字段集,无论照片是如何拍摄的。
Photo 字段 | MediaResult 等效字段 |
|---|---|
path | uri |
webPath | webPath |
base64String | thumbnail(在 Web 上包含完整的 base64 编码图片;在原生平台上包含缩略图) |
dataUrl | 无直接等效项——请参阅下面的说明 |
saved | saved |
format | metadata.format(需要 includeMetadata: true) |
exif | metadata.exif(需要 includeMetadata: true) |
构造 data URL——根据您的需求有两种选择:
在所有平台上,您可以结合使用 thumbnail 和 metadata.format(需要 includeMetadata: true)。在原生平台上,thumbnail 是较低分辨率的:
const dataUrl = `data:image/${result.metadata.format};base64,${result.thumbnail}`;
在原生平台上,如果您需要全分辨率的 base64,请通过 Filesystem API 读取 uri 并从中构造 data URL:
import { Filesystem } from '@capacitor/filesystem';
const { data } = await Filesystem.readFile({ path: result.uri });
const dataUrl = `data:image/${result.metadata.format};base64,${data}`;
替换 pickImages → chooseFromGallery
pickImages 允许从相册中选择多张照片。向 chooseFromGallery 传递 allowMultipleSelection: true 以获得相同的行为。
// 之前
const { photos } = await Camera.pickImages({
quality: 90,
limit: 5,
width: 1280,
height: 720,
});
for (const photo of photos) {
console.log(photo.webPath);
}
// 之后
const { results } = await Camera.chooseFromGallery({
allowMultipleSelection: true,
quality: 90,
limit: 5,
targetWidth: 1280, // 替换 width (1)
targetHeight: 720, // 替换 height (1)
});
for (const result of results) {
console.log(result.webPath);
}
(1) width/height 各自独立工作,在保持宽高比的同时设置最大尺寸。targetWidth/targetHeight 必须一起使用——仅设置一个无效。
chooseFromGallery 还可以通过设置 mediaType 为 MediaTypeSelection.Video 或 MediaTypeSelection.All 来选择视频或混合媒体。
选项重命名摘要
| 旧选项 | 新选项 | 适用范围 |
|---|---|---|
width | targetWidth (1) | takePhoto, chooseFromGallery |
height | targetHeight (1) | takePhoto, chooseFromGallery |
direction | cameraDirection | takePhoto |
allowEditing | editable: 'in-app' | takePhoto, chooseFromGallery |
resultType | —(已移除,见 结果类型变更) | — |
source | —(已移除,请使用独立方法) | — |
promptLabel* | —(已移除,请构建自己的 UI) | — |
(1) width/height 各自独立工作,在保持宽高比的同时设置最大尺寸。targetWidth/targetHeight 必须一起使用——仅设置一个无效。
API 参考
有关现有错误代码的列表,请参阅 错误。
takePhoto(...)
takePhoto(options: TakePhotoOptions) => Promise<MediaResult>
打开设备相机并允许用户拍照。
| Param | Type |
|---|---|
options | TakePhotoOptions |
返回: Promise<MediaResult>
自版本: 8.1.0
recordVideo(...)
recordVideo(options: RecordVideoOptions) => Promise<MediaResult>
打开设备相机并允许用户录制视频。 在 Web 上不可用。
| Param | Type |
|---|---|
options | RecordVideoOptions |
返回: Promise<MediaResult>
自版本: 8.1.0
playVideo(...)
playVideo(options: PlayVideoOptions) => Promise<void>
打开原生视频播放器。 在 Web 上不可用。
| Param | Type |
|---|---|
options | PlayVideoOptions |
自版本: 8.1.0
chooseFromGallery(...)
chooseFromGallery(options: ChooseFromGalleryOptions) => Promise<MediaResults>
允许用户直接从相册中选择图片、视频或两者。
| Param | Type |
|---|---|
options | ChooseFromGalleryOptions |
返回: Promise<MediaResults>
自版本: 8.1.0
editPhoto(...)
editPhoto(options: EditPhotoOptions) => Promise<EditPhotoResult>
打开应用内屏幕,使用提供的 base64 字符串编辑给定的照片。 在 Web 上不可用。
| Param | Type |
|---|---|
options | EditPhotoOptions |
返回 : Promise<EditPhotoResult>
自版本: 8.1.0
editURIPhoto(...)
editURIPhoto(options: EditURIPhotoOptions) => Promise<MediaResult>
打开应用内屏幕,使用提供的 URI 编辑照片。 在 Web 上不可用。
| Param | Type |
|---|---|
options | EditURIPhotoOptions |
返回: Promise<MediaResult>
自版本: 8.1.0
pickLimitedLibraryPhotos()
pickLimitedLibraryPhotos() => Promise<GalleryPhotos>
允许用户更新其有限的照片库选择。 在选择器关闭后返回所有有限的照片。 如果用户授予了对照片的完全访问权限,则返回空数组。
返回: Promise<GalleryPhotos>
自版本: 4.1.0
getLimitedLibraryPhotos()
getLimitedLibraryPhotos() => Promise<GalleryPhotos>
返回从有限的照片库中选择的照片数组。
返回: Promise<GalleryPhotos>
自版本: 4.1.0