Mengakses kamera dan galeri media via facade NativePHP: permission flow iOS/Android, capture foto dari kamera, pick dari galeri, crop image, simpan lokal, dan upload saat online — dengan studi kasus fitur foto profil lengkap.

Setelah di episode 5 kita membangun UI dengan Blade & Livewire — navigasi, form handling, dan styling mobile — pada episode ini kita memasuki dunia device APIs: mengakses kamera dan media perangkat. Ini adalah langkah pertama NativePHP benar-benar terasa "native" — PHP kalian sekarang bisa mengontrol hardware perangkat.
Kamera adalah salah satu device API paling umum digunakan. Dari foto profil, scan QR code, hingga upload dokumentasi — hampir semua aplikasi mobile membutuhkan akses kamera. NativePHP menyediakan facade yang familier untuk developer Laravel.
Sebelum mengakses kamera, aplikasi harus meminta permission dari user. Ini berbeda antara iOS dan Android:
Tambahkan deskripsi permission di Info.plist (atau via config/nativephp.php):
<?php
return [
'ios' => [
'permissions' => [
'NSCameraUsageDescription' => 'Aplikasi membutuhkan akses kamera untuk mengambil foto profil',
'NSPhotoLibraryUsageDescription' => 'Aplikasi membutuhkan akses galeri untuk memilih foto',
],
],
];iOS menampilkan dialog permission hanya satu kali — jika user menolak, kalian harus mengarahkan mereka ke Settings secara manual.
<?php
return [
'android' => [
'permissions' => [
'android.permission.CAMERA',
'android.permission.READ_EXTERNAL_STORAGE',
],
],
];Android 13+ menggunakan permission granular: READ_MEDIA_IMAGES untuk gambar, READ_MEDIA_VIDEO untuk video.
NativePHP menyediakan facade untuk mengakses kamera:
<?php
namespace App\Livewire;
use Livewire\Component;
use Native\Laravel\Facades\Camera;
class ProfilePhoto extends Component
{
public $photoPath;
public function takePhoto()
{
// Minta permission kamera
$granted = Camera::requestPermission();
if (!$granted) {
session()->flash('error', 'Permission kamera ditolak');
return;
}
// Ambil foto dari kamera
$photo = Camera::capture();
if ($photo) {
$path = $photo->storePublicly('profile-photos', 'local');
$this->photoPath = $path;
}
}
public function pickFromGallery()
{
$photo = Camera::fromGallery();
if ($photo) {
$path = $photo->storePublicly('profile-photos', 'local');
$this->photoPath = $path;
}
}
public function render()
{
return view('livewire.profile-photo');
}
}Camera::capture() membuka aplikasi kamera default perangkat, memungkinkan user mengambil foto, dan mengembalikan file image yang bisa disimpan menggunakan storage Laravel.
Implementasikan fitur foto profil end-to-end: ambil dari kamera atau galeri, crop, simpan lokal, dan upload saat online:
<?php
namespace App\Livewire;
use Livewire\Component;
use Native\Laravel\Facades\Camera;
use Illuminate\Support\Facades\Storage;
class ProfilePhoto extends Component
{
public $photoPath;
public $isUploading = false;
public function takePhoto()
{
$photo = Camera::capture([
'quality' => 0.8,
'maxWidth' => 1024,
'maxHeight' => 1024,
]);
if ($photo) {
$this->photoPath = $photo->store('profile-photos', 'local');
$this->dispatch('photo-taken', path: $this->photoPath);
}
}
public function pickFromGallery()
{
$photo = Camera::fromGallery([
'quality' => 0.8,
'maxWidth' => 1024,
]);
if ($photo) {
$this->photoPath = $photo->store('profile-photos', 'local');
}
}
public function uploadToServer()
{
if (!$this->photoPath) return;
$this->isUploading = true;
try {
$file = Storage::disk('local')->get($this->photoPath);
$filename = basename($this->photoPath);
// Upload ke server backend
http::attach('photo', $file, $filename)
->post('https://api.myapp.com/profile/photo', [
'user_id' => auth()->id(),
]);
session()->flash('success', 'Foto profil berhasil diupload');
} catch (\Exception $e) {
session()->flash('error', 'Upload gagal: ' . $e->getMessage());
} finally {
$this->isUploading = false;
}
}
public function render()
{
return view('livewire.profile-photo');
}
}Pola ini menerapkan offline-first: foto disimpan lokal dulu, kemudian di-upload ke server saat koneksi tersedia. Kita dalami strategi sync ini di episode 15.
Setiap operasi kamera bisa gagal — permission ditolak, kamera tidak tersedia, atau storage penuh. Selalu handle error:
try {
$photo = Camera::capture();
} catch (CameraUnavailableException $e) {
session()->flash('error', 'Kamera tidak tersedia di perangkat ini');
} catch (PermissionDeniedException $e) {
session()->flash('error', 'Permission kamera ditolak. Aktifkan di Settings.');
} catch (StorageException $e) {
session()->flash('error', 'Storage penuh. Hapus beberapa file terlebih dahulu.');
}Warning
Jangan pernah mengasumsikan kamera tersedia. Beberapa perangkat (tablet, emulator tanpa camera) mungkin tidak punya kamera. Selalu cek Camera::isAvailable() sebelum memanggil capture().
Inti yang harus dibawa pulang:
Info.plist (iOS) dan AndroidManifest (Android).capture(), fromGallery(), dan requestPermission().Di episode 7 selanjutnya, kita akan membahas Biometrics & Secure Storage — Face ID, Touch ID, fingerprint via Biometric facade, dan secure storage untuk token/secret menggunakan Keychain (iOS) / Keystore (Android). Sampai jumpa di episode 7!