Akses Hardware: Camera, GPS & Sensors
Salah satu keunggulan utama mobile app dibanding web app adalah akses penuh ke hardware device. Expo menyediakan API yang konsisten untuk camera, location, dan berbagai sensor.
Camera dengan expo-camera
import { CameraView, useCameraPermissions } from 'expo-camera';
import { useState, useRef } from 'react';
export default function CameraScreen() {
const [permission, requestPermission] = useCameraPermissions();
const [facing, setFacing] = useState('back');
const cameraRef = useRef(null);
if (!permission) return <View />;
if (!permission.granted) {
return (
<View>
<Text>Butuh izin akses kamera</Text>
<Pressable onPress={requestPermission}>
<Text>Grant Permission</Text>
</Pressable>
</View>
);
}
const takePicture = async () => {
const photo = await cameraRef.current?.takePictureAsync();
console.log('Photo URI:', photo.uri);
};
return (
<CameraView ref={cameraRef} style={{ flex: 1 }} facing={facing}>
<Pressable onPress={takePicture}>
<Text>Take Photo</Text>
</Pressable>
</CameraView>
);
}
Location dengan expo-location
import * as Location from 'expo-location';
async function getCurrentLocation() {
// Request permission
const { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
alert('Permission denied');
return;
}
// Get current position
const location = await Location.getCurrentPositionAsync({
accuracy: Location.Accuracy.High,
});
console.log('Latitude:', location.coords.latitude);
console.log('Longitude:', location.coords.longitude);
return location;
}
// Watch position (real-time tracking)
const subscription = await Location.watchPositionAsync(
{ accuracy: Location.Accuracy.High, distanceInterval: 10 },
(location) => {
console.log('Moved to:', location.coords);
}
);
// Geocoding (koordinat → alamat)
const address = await Location.reverseGeocodeAsync({
latitude: -6.2088,
longitude: 106.8456,
});
console.log(address[0].city); // 'Jakarta'
Sensors
import { Accelerometer, Gyroscope } from 'expo-sensors';
// Accelerometer — deteksi gerakan/guncangan
Accelerometer.setUpdateInterval(100); // ms
const subscription = Accelerometer.addListener(({ x, y, z }) => {
// Shake detection
const totalForce = Math.sqrt(x * x + y * y + z * z);
if (totalForce > 2.5) {
console.log('Device shaken!');
}
});
// Cleanup
subscription.remove();
Image Picker
import * as ImagePicker from 'expo-image-picker';
async function pickImage() {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ['images'],
allowsEditing: true,
aspect: [1, 1],
quality: 0.8,
});
if (!result.canceled) {
console.log('Selected:', result.assets[0].uri);
}
}
Permission Pattern
- Selalu request permission sebelum akses hardware — User harus explicitly grant
- Handle denied gracefully — Jelaskan kenapa app butuh permission, arahkan ke Settings
- Foreground vs Background — Location background butuh permission terpisah dan justifikasi ke App Store
- Minimal permission — Hanya minta yang benar-benar dibutuhkan