본문 바로가기

React & React-native

< React-native > / expo-camera보다 가벼운 expo-imagepicker / 핸드폰 카메라 권한 설정하기 / 앨범에 있는 사진 올리기/ 권한 설정

앱의 카메라로 찍은 사진을 사용하고 싶지만, 카메라 자체의 세부적인 설정까지 하기 어려울때!!

기본카메라로 찍은 사진만 사용해도 괜찮을 때 쓰면 간편한 라이브러리를 소개한다.

 

- 설치 환경 :  expo 

* 만약 bare라던가 날것의 react-native라면 추가적인 설정이 필요하다. 공식 문서에 있다

참고 : https://github.com/expo/expo/tree/sdk-47/packages/expo-image-picker

 

1. 설치

npx expo install expo-image-picker

위의 명령어로 설치를 해준다음 app.json 파일에 설정을 추가로 해줘야한다.

 

{
  "expo": {
    "plugins": [
      [
        "expo-image-picker",
        {
          "cameraPermission": "Spot 등록을 위해 카메라 접근권한을 허용해주세요.",
          "photosPermission": "Spot 등록을 위해 앨범 접근권한을 허용해주세요"
        }
      ]
    ]
  }
}

 

플러그 인부분만 복붙하면 된다. 혹시 어디에 할지 모르는 사람을 위해 

 

 

 

<app.json 전문>

 

 

이렇게 붙여 넣으면 된다!

+ 기본적으로 photosPermission (사진 사용권한, 앨범에 있는 사진 올리기) 을 요청하는데 나는 카메라 사용자체도 요청할 것이기 때문에 

수정해주었다. 공식문서에 보면 나와있다!

 

 

 

2.  ImagePicker.js 만들어주기

설치를 해준다음 이 플러그인을 사용하기 위해 따로 js 파일도 생성해줘야한다. 

사진선택 버튼과 해당 버튼을 눌렀을 때, 권한을 요청하는 함수를 설정해줘야한다.

 

 

import { Alert, Button, Image, StyleSheet, Text, View } from 'react-native';
import {
  launchCameraAsync,
  useCameraPermissions,
  PermissionStatus,
  requestMediaLibraryPermissionsAsync,
  useMediaLibraryPermissions,
  launchImageLibraryAsync,
  MediaTypeOptions,
} from 'expo-image-picker';
import { useState } from 'react';


function ImagePicker({userPickImage}) {
  const [pickedImage, setPickedImage] = useState();

  const [cameraPermissionInformation, requestPermission] = useCameraPermissions();
  const [albumPermissionInfomation, requestAlbumPermission] = useMediaLibraryPermissions();

    // 카메라 접근 권한요청
  async function verifyPermissions() {
    if (cameraPermissionInformation.status === PermissionStatus.UNDETERMINED) {
      const permissionResponse = await requestPermission();

      return permissionResponse.granted;
    }

    if (cameraPermissionInformation.status === PermissionStatus.DENIED) {
      Alert.alert(
        '권한이 필요합니다!',
        'Spot을 등록하려면 카메라 접근권한이 필요합니다..'
      );
      return false;
    }
    return true;
  }


  // 앨범 접근권한 요청
async function albumVerifyPermissions(){
  if(albumPermissionInfomation.status === PermissionStatus.UNDETERMINED){
    const permissionResponse = await requestAlbumPermission();

    return permissionResponse.granted;
  }
  if(albumPermissionInfomation.status === PermissionStatus.DENIED){
    Alert.alert('권한이 필요합니다!', 'spot을 등록하려면 사진 접근권한이 필요합니다.');
    return false;
  }
  return true;
}

// 카메라로 사진 이미지 사용관련
  async function takeImageHandler() {
    const hasPermission = await verifyPermissions();

    if (!hasPermission) {
      return;
    }

    const image = await launchCameraAsync({
      allowsEditing: true, // 사진자르기 허용
      aspect: [16, 9], // 사진품질설정
      quality: 0.5,
    });

    setPickedImage(image.uri);
    userPickImage(image.uri);
  }


    // 앨범 이미지 사용 관련
  async function albumImageHandler(){
    const hasPermission = await albumVerifyPermissions();

    if(!hasPermission){
      return;
    }

    const image = await launchImageLibraryAsync({
      mediaTypes: MediaTypeOptions.Images, // 사진만 허용
      allowsEditing: true,
      aspect: [16, 9], // 사진 비율 설정
      quality: 1, // 용량
    });

    setPickedImage(image.uri);
    userPickImage(image.uri);
  }




  let imagePreview = <Text>No image taken yet.</Text>;

  if (pickedImage) {
    imagePreview = <Image style={styles.image} source={{ uri: pickedImage }} />;
  }

  return (
    <View>
      <View style={styles.imagePreview}>{imagePreview}</View>
      <View style={styles.buttonContainer}>
        <Button title="Camera" onPress={takeImageHandler} />
        <Button title="앨범에서 가져오기" onPress={albumImageHandler} />
      </View>
    </View>
  );
}

export default ImagePicker;

const styles = StyleSheet.create({
  imagePreview: {
    width: '100%',
    height: 200,
    marginVertical: 8,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'white',
    borderRadius: 4,
  },
  image: {
    width: '100%',
    height: '100%',
  },
  buttonContainer:{
    justifyContent: 'space-evenly',
    alignItems:'center',
    flexDirection:'row',
    marginVertical: 7,
    marginHorizontal: 5,
  }
});

 

조금 길지만 중요부분에 주석을 써놨으니 알아보기 어렵지 않을 것이다.

 

 

 

 

 

그리고 이렇게 다른 컴포넌트를 사용하는 것처럼 import해서 사용하면 끝이다!

 

 

혹시 몰라서 내가 사용한 곳의 코드도 전문 첨부해둔다.

 

<사용한 곳 전문>

 

// 스팟 등록할 때 입력사항들

import { View, Text, TextInput, ScrollView } from "react-native";
import { useCallback, useState } from 'react';
import ImagePicker from './ImagePicker';
import { StyleSheet } from 'react-native';
import LocationPicker from './LocationPicker';
import Button from './../ui/Button';
import { Spot } from '../../models/spot';



// 스팟 등록할 때
function SpotForm({createSpotHandler}){
    const [enteredTitle, setEnteredTitle] = useState('');
    const [pickedImage, setPickedImage] = useState();
    const [pickedLocation, setPickedLocation] = useState();
    const [enteredDescription,  setEnteredDescription] = useState();

    function changeTitleHandler(enteredText){
        setEnteredTitle(enteredText)
    }

    function pickedImageHandler(imageURL){
        setPickedImage(imageURL);
    }

    function describtionHandler(enteredDescription){
        setEnteredDescription(enteredDescription);
    }

    const pickedLocationHandler = useCallback((location) => {
        setPickedLocation(location);
    },[]);


    function savePlaceHandler(){
        console.log(enteredTitle);
        console.log(pickedImage);
        console.log(pickedLocation); // 정상적으로 다 들어옴

        //constructor(title, imgURL, address, location, description) 정의한대로 데이터 모으기
        const spotData = new Spot(enteredTitle, pickedImage, pickedLocation, enteredDescription);
        // addSpot.js에 있음
        createSpotHandler(spotData);
    }

    return(
        <ScrollView >
            <View style={styles.form}>
            <View>
                <Text style={styles.label}>Spot 명</Text>
                <TextInput style={styles.input} onChangeText={changeTitleHandler} value={enteredTitle} />
            </View>
            <ImagePicker userPickImage={pickedImageHandler}/>
            <LocationPicker userPickLocation={pickedLocationHandler}/>
            <Text style={styles.label}>Spot 설명</Text>
            <TextInput style={styles.input} onChangeText={describtionHandler} value={enteredDescription}></TextInput>
            <Button onPress={savePlaceHandler}>Spot 등록</Button>
            </View>
        </ScrollView>
    )
}

export default SpotForm;


const styles = StyleSheet.create({
    form:{
        flex: 1,
        padding:24,
    },
    label:{
        fontWeight: 'bold',
        marginBottom: 4,
        color: '#ffff'
    },
    input:{
        marginVertical: 8,
        paddingHorizontal: 4,
        paddingVertical: 8,
        fontSize: 16,
        borderBottomColor: 'blue',
        borderBottomWidth:2,
        backgroundColor: 'green',
    }

})

 

 

 

 

 

728x90