이전 글에서 간단하게 리액트 네이티브(React Native), Expo에서의 CAMERA 퍼미션에 대한 글을 작성하였다.

오늘은 실제로는 카메라, 갤러리 둘 다 접근할 수 있으므로, 유동적으로 카메라와 갤러리를 선택하고, 각각의 퍼미션을 따로 체크하는 과정에 대한 부분을 코딩해 보았다.

일단, asyncawait에 대한 개념의 이해가 필요한데 여기로 가면 자세히 알 수 있다.

과정

  1. 버튼을 만든다.
  2. 버튼을 누르면, Alert가 뜬다. Camera, Gallery 선택 가능.
  3. 각각의 퍼미션을 체크한 후, 체크 완료시, Camera와 Gallery로 이동한다.

일단, Camera와 Gellery를 둘 다 사용할 것이기 때문에 app.json에 가서 아래와 같이 등록해 준다.

"android": {
  "permissions": [
    "CAMERA",
    "CAMERA_ROLL",
  ],
},

그리고 Permission체크를 각각 따로 다 만들 수 없기에 하나로 묶어서 체크하는 함수를 만든다.

//type : CAMERA => 0, CAMERA_ROLL => 1
//p_type : getAsync => 0, askAsync => 1

getPermissionStatus(type, p_type) {
  const { Permissions } = Expo;
  if(p_type == 0) {
    if(type == 0) {
      return Permissions.getAsync(Permissions.CAMERA);
    }
    else {
      return Permissions.getAsync(Permissions.CAMERA_ROLL);
    }
  }
  else {
    if(type == 0) {
      return Permissions.askAsync(Permissions.CAMERA);
    }
    else {
      return Permissions.askAsync(Permissions.CAMERA_ROLL);
    }
  }
}

이렇게 한 후, Alert에서 클릭했을 때, 퍼미션 체크 및 그 이후 카메라 화면 또는 갤러리 화면을 보여주는 함수를 코딩한다.

// type : CAMERA => 0, GALLERY => 1

async checkPermisson(type) {
  let { status } = await this.getPermissionStatus(type, 0);
  if (status !== 'granted') {
    status = await this.getPermissionStatus(type, 1);
  }

  if (status === 'granted') {
    if(type == 0) {
      this.setState({ status: status === 'granted' });
      this.props.navigation.navigate('Camera', { name: 'Jane' })
    }
    else {
      this.setState({ status: status === 'granted' });
      if(this.state.status) {
        this.pickImage();
      }
    }
  }
}

위의 처럼 코딩하면 허용을 해도… askAsync에서 넘어온 status는 'granted'가 아니다.

async checkPermisson(type) {
  const { status } = await this.getPermissionStatus(type, 0);
  this.setState({ status: status === 'granted' });
  if (status !== 'granted') {
    const { status } = await this.getPermissionStatus(type, 1);
    this.setState({ status: status === 'granted' });
  }

  if (this.state.status) {
    if(type == 0) {

      this.props.navigation.navigate('Camera', { name: 'Jane' })
    }
    else {
      this.pickImage();
    }
  }
}

위의 부분에서의 const { status }const { a_status } 등의 변수로 변해도 'granted‘라는 값이 들어오지 않는다. 이유를 모르겠지만… 일단 퍼미션 받아올 때는 무조건 const { status } 라는 변수로 사용해야 하는 것 같다.

그리고는, Alert를 띄우는 함수, 카메라 화면, 갤러리 화면 등의 그 외 구현해야할 뷰를 구현하면 된다. 카메라 스크린에 대한 코드는 Expo 예제 코드를 사용하였다.

//...

async pickImage() {
  let result = await ImagePicker.launchImageLibraryAsync({
    allowsEditing: true,
    aspect: [4, 3],
  });

  console.log(result);

  if (!result.cancelled) {
    this.setState({ image: result.uri });
  }
}

showAlert() {
  Alert.alert(
    null,
    'Select menu',
    [
      {text: 'Camera', onPress: () => this.checkPermisson(0)},
      {text: 'Gallery', onPress: () => this.checkPermisson(1)},
    ],
    { cancelable: true }
  )
}

render() {
  let { navigate } = this.props.navigation;
  return (
    <View style={styles.container}>
        <Button
          title= "Select image"
          onPress={() => {
              this.showAlert();
            }
          }
        />
    </View>
  );
}

// ...

asyncawait의 개념의 이해 후에 조금 코드가 깔끔하게 정리되었다. Javascript의 공부없이 무작정 따라가려고 하니까 정말 힘들다…