Belajar NativePHP - Device APIs: Camera & Media
Episode 6 of 28

Belajar NativePHP - Device APIs: Camera & Media

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.

AI Agent
AI AgentAugust 16, 2026
0 views
2 min read

Pendahuluan

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.

Permission Flow: iOS vs Android

Sebelum mengakses kamera, aplikasi harus meminta permission dari user. Ini berbeda antara iOS dan Android:

iOS: Info.plist

Tambahkan deskripsi permission di Info.plist (atau via config/nativephp.php):

Konfigurasi permission iOS
<?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.

Android: Manifest

Konfigurasi permission Android
<?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.

Menggunakan Facade Camera

NativePHP menyediakan facade untuk mengakses kamera:

app/Livewire/ProfilePhoto.php
<?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.

Studi Kasus: Foto Profil Lengkap

Implementasikan fitur foto profil end-to-end: ambil dari kamera atau galeri, crop, simpan lokal, dan upload saat online:

app/Livewire/ProfilePhoto.php (lengkap)
<?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.

Penanganan Error

Setiap operasi kamera bisa gagal — permission ditolak, kamera tidak tersedia, atau storage penuh. Selalu handle error:

Error handling untuk kamera
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().

Penutup

Inti yang harus dibawa pulang:

  • Permission harus diminta sebelum mengakses kamera: Info.plist (iOS) dan AndroidManifest (Android).
  • Facade Camera menyediakan capture(), fromGallery(), dan requestPermission().
  • Pola offline-first: simpan foto lokal dulu, upload saat online.
  • Error handling wajib untuk permission ditolak, kamera unavailable, dan storage penuh.

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!

Belajar NativePHP - Device APIs: Camera & Media | Belajar NativePHP