Mengintegrasikan `@capacitor/camera` untuk mengambil foto dari kamera atau galeri, `@capacitor/filesystem` untuk membaca dan menulis file di storage native, lalu membangun fitur upload foto avatar end-to-end.

Setelah di episode 5 kita memahami plugin system dan mengintegrasikan core plugins, pada episode ini kita mendalami tiga plugin yang paling sering dipakai di aplikasi mobile: Camera, Filesystem, dan Media. Ketiganya sering digunakan bersamaan — ambil foto dari kamera, simpan ke storage, lalu tampilkan atau upload.
Mengapa topik ini penting? Karena hampir semua aplikasi mobile memiliki fitur yang melibatkan foto atau file: profil user, upload dokument, scan dokumen, dan banyak lagi. Memahami alur camera → filesystem → network adalah pola fundamental.
npm install @capacitor/camera
npx cap syncSebelum mengambil foto, kalian harus meminta izin. Di iOS, permission didefinisikan di Info.plist. Di Android, didefinisikan di AndroidManifest.xml. Capacitor menangani ini otomatis saat plugin dipanggil pertama kali.
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
async function takePhoto() {
const photo = await Camera.getPhoto({
quality: 90,
allowEditing: true,
resultType: CameraResultType.Uri,
source: CameraSource.Camera,
});
// photo.webPath berisi URI file yang bisa ditampilkan di <img>
return photo.webPath;
}| Source | Deskripsi |
|---|---|
CameraSource.Camera | Buka kamera langsung |
CameraSource.Photos | Buka galeri foto |
CameraSource.Prompt | Tampilkan dialog pilihan ke user |
Jika kalian perlu mengirim foto ke server sebagai base64:
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
async function getPhotoBase64() {
const photo = await Camera.getPhoto({
quality: 80,
allowEditing: false,
resultType: CameraResultType.Base64,
source: CameraSource.Camera,
});
// photo.base64String berisi data base64 tanpa prefix
const base64Data = `data:image/jpeg;base64,${photo.base64String}`;
return base64Data;
}npm install @capacitor/filesystem
npx cap syncimport { Filesystem, Directory, Encoding } from '@capacitor/filesystem';
// Tulis file
await Filesystem.writeFile({
path: 'notes/my-note.txt',
data: 'Hello from Capacitor!',
directory: Directory.Data,
encoding: Encoding.UTF8,
});
// Baca file
const contents = await Filesystem.readFile({
path: 'notes/my-note.txt',
directory: Directory.Data,
encoding: Encoding.UTF8,
});
console.log('File contents:', contents.data);| Directory | Lokasi | Penggunaan |
|---|---|---|
Directory.Data | App sandbox | Data internal aplikasi |
Directory.Cache | Cache directory | File sementara yang bisa dihapus sistem |
Directory.Documents | Documents directory | File yang bisa diakses user |
Directory.External | External storage (Android) | Storage publik (butuh permission) |
import { Filesystem, Directory } from '@capacitor/filesystem';
// Cek apakah file ada
const stat = await Filesystem.stat({
path: 'notes/my-note.txt',
directory: Directory.Data,
});
// Hapus file
await Filesystem.deleteFile({
path: 'notes/my-note.txt',
directory: Directory.Data,
});
// Baca isi direktori
const dirContents = await Filesystem.readdir({
path: 'notes',
directory: Directory.Data,
});
console.log('Files:', dirContents.files);Berikut contoh lengkap alur ambil foto → simpan lokal → tampilkan:
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { Filesystem, Directory } from '@capacitor/filesystem';
async function uploadAvatar() {
// 1. Ambil foto dari kamera
const photo = await Camera.getPhoto({
quality: 80,
allowEditing: true,
resultType: CameraResultType.Base64,
source: CameraSource.Camera,
});
// 2. Simpan ke filesystem
const fileName = `avatar-${Date.now()}.jpg`;
await Filesystem.writeFile({
path: `avatars/${fileName}`,
data: photo.base64String!,
directory: Directory.Data,
});
// 3. Baca kembali untuk ditampilkan
const file = await Filesystem.readFile({
path: `avatars/${fileName}`,
directory: Directory.Data,
});
// 4. Tampilkan di UI
const avatarUrl = `data:image/jpeg;base64,${file.data}`;
return avatarUrl;
}Tip
Untuk upload ke server, kirim base64 sebagai body POST atau convert ke Blob terlebih dulu. Untuk file besar, pertimbangkan chunked upload atau streaming — topik yang kita bahas di episode 10.
Kedua plugin membutuhkan permission. Capacitor menangani permission dialog secara otomatis, tetapi kalian bisa memeriksa status permission:
import { Camera } from '@capacitor/camera';
const status = await Camera.checkPermissions();
if (status.camera === 'denied' || status.photos === 'denied') {
// Minta ulang permission
const newStatus = await Camera.requestPermissions();
if (newStatus.camera === 'denied') {
// Arahan user ke settings
console.log('Permission ditolak. Buka settings untuk mengaktifkan.');
}
}Pada episode 6 ini, kalian telah memahami:
@capacitor/camera mengambil foto dari kamera atau galeri dengan berbagai CameraResultType.@capacitor/filesystem membaca dan menulis file di sandbox native.Di episode 7 selanjutnya, kita akan membahas Geolocation, Preferences, dan Local Storage — akses GPS untuk tracking lokasi, key-value storage persisten, serta strategi storage什么时候 pakai Preferences vs IndexedDB vs SQLite. Sampai jumpa!