Фото из галереи и камеры
Возможности телефона — камера, геолокация, контакты, вибрация — доступны через модули Expo. Каждый модуль — пакет с JavaScript-функциями, за которыми стоит родной код iOS и Android. Разберём на примере expo-image-picker: пользователь выберет аватар для профиля в блоге.
Установка
npx expo install expo-image-pickerМодуль уже есть внутри Expo Go, поэтому работает сразу после установки пакета.
Выбор из галереи
// app/(tabs)/profile.tsx
import { Image } from 'expo-image';
import * as ImagePicker from 'expo-image-picker';
import { useState } from 'react';
import { Button, View } from 'react-native';
export default function Profile() {
const [avatar, setAvatar] = useState<string | null>(null);
async function pickImage() {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ['images'],
allowsEditing: true,
aspect: [1, 1],
quality: 0.8,
});
if (!result.canceled) {
setAvatar(result.assets[0].uri);
}
}
return (
<View style={{ flex: 1, alignItems: 'center', padding: 16, gap: 12 }}>
{avatar && <Image source={avatar} style={{ width: 120, height: 120, borderRadius: 60 }} />}
<Button title="Выбрать фото" onPress={pickImage} />
</View>
);
}Нажмите «Выбрать фото» — откроется системная галерея. После выбора появится окно обрезки до квадрата (aspect: [1, 1]), а затем круглый аватар над кнопкой. uri — адрес файла на телефоне, его можно показать в Image или отправить на сервер.
Параметры
| Параметр | Что задаёт |
|---|---|
mediaTypes | Что выбирать: ['images'], ['videos'] или оба |
allowsEditing | Показать экран обрезки |
aspect | Пропорции обрезки, например [4, 3] |
quality | Качество сжатия от 0 до 1 |
Если пользователь закрыл галерею, result.canceled равен true, а assets нет.
Съёмка камерой
Для камеры нужно разрешение пользователя. Его запрашивают перед съёмкой:
// app/(tabs)/profile.tsx
async function takePhoto() {
const permission = await ImagePicker.requestCameraPermissionsAsync();
if (!permission.granted) {
Alert.alert('Нет доступа к камере');
return;
}
const result = await ImagePicker.launchCameraAsync({ allowsEditing: true, aspect: [1, 1] });
if (!result.canceled) {
setAvatar(result.assets[0].uri);
}
}Добавьте кнопку <Button title="Сделать фото" onPress={takePhoto} /> и Alert в импорт. При первом нажатии система спросит разрешение, затем откроется камера. В iOS-симуляторе камеры нет — проверяйте на телефоне.
Текст запроса разрешения
Текст системного окна задают в app.json через плагин модуля:
{
"expo": {
"plugins": [
["expo-image-picker", { "cameraPermission": "Камера нужна, чтобы сделать фото для профиля." }]
]
}
}Этот текст попадает в приложение при сборке через EAS; в Expo Go показывается стандартный текст Expo Go.
Частая ошибка
Не проверять result.canceled и сразу читать result.assets[0].uri. Если пользователь закрыл галерею без выбора, assets равен null, и приложение упадёт с ошибкой. Всегда проверяйте отмену перед использованием результата.