@capacitor/camera
カメラAPIは、カメラで写真を撮影したり、フォトアルバムから既存の写真を選択する機能を提供します。
Install
npm install @capacitor/camera
npx cap sync
iOS
iOSでは、Info.plistにアプリ用の以下の使用説明を追加して記入する必要があります:
NSCameraUsageDescription(Privacy - Camera Usage Description)NSPhotoLibraryAddUsageDescription(Privacy - Photo Library Additions Usage Description)NSPhotoLibraryUsageDescription(Privacy - Photo Library Usage Description)
XcodeでのiOSパーミッションの設定については、iOSガイドのInfo.plistの設定を参照してください。
Android
デバイスギャラリーから既存の画像を選択する際、AndroidフォトピッカーコンポーネントがAndroidでは使用されるようになりました。フォトピッカーは以下の条件を満たすデバイスで利用できます:
- Android 11(APIレベル30)以上を実行している
- Google Systemアップデートを通じてモジュラーシステムコンポーネントの変更を受信している
Android 11または12を実行しているGoogle Playサービスをサポートする古いデバイスやAndroid Goデバイスでは、バックポートされたフォトピッカーをインストールできます。Google Playサービスを通じてバックポートされたフォトピッカーモジュールの自動インストールを有効にするには、AndroidManifest.xmlファイルの<application>タグに以下のエントリを追加します:
<!-- Trigger Google Play services to install the backported photo picker module. -->
<!--suppress AndroidDomInspection -->
<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>
そのエントリが追加されていない場合、フォトピッカーをサポートしていないデバイスでは、フォトピッカーコンポーネントは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を起動するため、Activityの実行中にOSによってアプリが終了された場合に送信されたカメラデータを処理するために、AppプラグインのappRestoredResultをリッスンする必要があります。
Variables
このプラグインは以下のプロジェクト変数(アプリの variables.gradle ファイルで定義)を使用します:
androidxExifInterfaceVersion:androidx.exifinterface:exifinterfaceのバージョン(デフォルト:1.4.2)androidxMaterialVersion:com.google.android.material:materialのバージョン(デフォルト:1.14.0)
PWAに関する注意事項
Webでは、takePhoto は PWA Elements の pwa-camera-modal カスタム要素を使用して、ネイティブに近いカメラUIを提供できます。この要素が登録されていない場合、プラグインは <input type="file"> ピッカーにフォールバックします。chooseFromGallery は、PWA Elementsがインストールされているかどうかにかかわらず、Webでは常に <input type="file"> を使用します。
Installing PWA Elements programmatically
See the PWA Elements installation guide for full instructions.
Providing a custom camera element
Instead of using @ionic/pwa-elements, you can register your own pwa-camera-modal custom element. The plugin interacts with it using the following interface:
| Member | Type | Description |
|---|---|---|
facingMode | string property | Set to 'user' (front camera) or 'environment' (rear camera) before presenting |
componentOnReady() | method → Promise<void> | Called by the plugin after creating the element; resolve when the element is ready |
present() | method | Called by the plugin to display the camera UI |
dismiss() | method | Called by the plugin to close the camera UI after a photo is taken or cancelled |
onPhoto | event | Dispatched when the user takes a photo or cancels. event.detail must be a Blob (photo taken), null (user cancelled), or an Error (something went wrong) |
class MyCameraModal extends HTMLElement {
facingMode = 'environment';
componentOnReady() {
return Promise.resolve();
}
present() {
// Show your custom camera UI, then dispatch exactly one 'onPhoto' event when done:
// - Blob: user took a photo
// - null: user cancelled
// - Error: something went wrong
// Example:
this.dispatchEvent(new CustomEvent('onPhoto', { detail: photoBlob }));
}
dismiss() {
// Hide your custom camera UI (called by the plugin after receiving 'onPhoto')
}
}
customElements.define('pwa-camera-modal', MyCameraModal);
Examples
Taking a photo
import { Camera } from '@capacitor/camera';
const takePicture = async () => {
try {
const result = await Camera.takePhoto({
quality: 90,
includeMetadata: true,
});
// result.webPath can be set directly as the src of an image element
imageElement.src = result.webPath;
// On native: pass result.uri to the Filesystem API to get the full-resolution base64,
// or use result.thumbnail for a lower-resolution base64 preview.
// On Web: result.thumbnail contains the full image base64 encoded.
console.log('Format:', result.metadata?.format);
console.log('Resolution:', result.metadata?.resolution);
} catch (e) {
const error = e as any;
// error.code contains the structured error code (e.g. 'OS-PLUG-CAMR-0003')
// when thrown by the native layer. See the Errors section for all codes.
const message = error.code ? `[${error.code}] ${error.message}` : error.message;
console.error('takePhoto failed:', message);
}
};
Choosing from the gallery
import { Camera, MediaTypeSelection } from '@capacitor/camera';
const pickMedia = async () => {
try {
const { results } = await Camera.chooseFromGallery({
mediaType: MediaTypeSelection.All, // photos, videos, or both
allowMultipleSelection: true,
limit: 5,
includeMetadata: true,
});
for (const item of results) {
console.log('Type:', item.type); // MediaType.Photo or 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);
}
};
Recording and playing a video
import { Camera } from '@capacitor/camera';
const recordAndPlay = async () => {
let videoUri: string | undefined;
try {
const result = await Camera.recordVideo({
saveToGallery: false,
isPersistent: true, // keep the file available across app launches
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);
}
}
};