react-native-fs 로 파일 저장,접근 하기

ios에서는 별도 파일로 출력없이 uri-data로 바로 사용해도 문제가 없었는데 안드로이드에서는 제대로 동작하지 않는다. 따라서 file-system을 이용하여 이미지를 저장하고, 불러와서 사용하는 형태로 수정한다.
 

React-Native-FS

설치 (RN ≥ 0.60 기준)

설치 과정 정리
# 패키지 추가 $ yarn add react-native-fs # ios pod 설치 <-- iOS는 여기까지하면 설치 끝. $ npx pod-install

안드로이드 추가 설정

안드로이드 추가 설정
  • android/settings.gradle
... //file system include ':react-native-fs' project(':react-native-fs').projectDir = new File(settingsDir, '../node_modules/react-native-fs/android')
notion image
 
  • android/app/build.gradle
dependencies { ... //file-system implementation project(':react-native-fs') }
notion image
 

디렉토리

플랫폼별 Native 폴더 연계 함수

공용 폴더

DocumentDirectoryPath
도큐먼트 폴더(Document Directory)의 절대 위치입니다.
CachesDirectoryPath
캐시 폴더(Cache Directory)의 절대 위치입니다.
TemporaryDirectoryPath
임시 폴더(Temporary Directory)의 절대 위치입니다.

iOS 전용폴더

(안드로이드는 캐시 폴더가 전달됩니다.)
MainBundlePath
메인 번들 폴더(Main Bundle Directory)의 절대 위치입니다.
(안드로이드에서는 사용이 불가능합니다.)
LibraryDirectoryPath
iOS의 NSLibraryDirectory의 절대 위치입니다.
(안드로이드에서는 사용이 불가능합니다.)

Android 전용폴더

ExternalCachesDirectoryPath
외부 캐시 폴더(External Cache Directory)의 절대 위치입니다.
(iOS에서는 사용이 불가능합니다.)
ExternalDirectoryPath
외부 파일 공유 폴더(External files, shared directory)의 절대 위입니다.
(iOS에서는 사용이 불가능합니다.)
ExternalStorageDirectoryPath
외부 저장소 공유 폴더(External storage, shared directory)의 절대 위치입니다.
(iOS에서는 사용이 불가능합니다.)

기능

공식 도큐먼트 보는게 더 빠름.
웬만한건 공통기능으로 구현 가능하다.
공통 기능
  • readDir(dirpath: string): 파라메터로 전달받은 절대 위치(Absolute path)의 폴더를 읽는다.
  • readdir(dirpath: string): Nodejs 스타일의 readDir
  • stat(filepath: string): 전달받은 파일 위치의 파일 상태를 가져온다.
  • readFile(filepath: string, encoding?: string): 전달 받은 파일 위치의 파일을 읽는다. encoding은 utf8(default), ascii, base64를 지원하며 base64는 바이너리 파일을 읽는데 사용된다.
  • read(filepath: string, length = 0, position = 0, encodingOrOptions?: any): 전달받은 파일 위치의 파일에 특정 위치(position)에서 길이(length)만큼 파일 내용을 읽어온다. encoding은 readFile과 동일하다.
  • writeFile(filepath: string, contents: string, encoding?: string): 지정한 파일 위치에 파일을 기록합니다.
  • appendFile(filepath: string, contents: string, encoding?: string): 지정한 파일에 전달한 파일 내용을 추가합니다.
  • write(filepath: string, contents: string, position?: number, encoding?: string): 파일의 특정 위치(position)에 전달받은 파일 내용을 추가합니다.
  • moveFile(filepath: string, destPath: string): 파일을 이동시킵니다.
  • copyFile(filepath: string, destPath: string): 파일을 복사합니다.
  • unlink(filepath: string): 파일을 삭제합니다.
  • exists(filepath: string): 파일의 존재 여부를 확인합니다. 파일이 존재하지 않는 경우 false를 반환합니다.
  • hash(filepath: string, algorithm: string): 전달받은 파일 위치의 파일에서 해당 알고리즘(algorithm)의 checksum을 반환합니다. 알고리즘(algorithm)에는 md5, sha1, sha224, sha256, sha384, sha512가 사용 가능합니다.
  • touch(filepath: string, mtime?: Date, ctime?: Date): 파일의 수정일(mtime)과 생성일(ctime)을 갱신합니다. iOS에서는 생성일(ctime)만 수정하는 것이 가능하며, 안드로이드에서는 수정일(mtime)을 이용하여 수정일과 생성일을 항상 동시에 갱신합니다.
  • mkdir(filepath: string, options?: MkdirOptions): 폴더를 생성합니다.
  • downloadFile(options: DownloadFileOptions): 전달받은 옵션(options)안의 파일 URL을 이용하여 파일을 다운로드합니다.
  • stopDownload(jobId: number): 전달받은 다운로드 아이디를 이용하여 다운로드를 중지합니다.
  • getFSInfo(): 파일 시스템의 정보(총 용량, 사용 가능한 용량)를 반환합니다.
안드로이드 전용 기능
  • existsAssets(filepath: string): (안드로이드) 안드로이드의 assets 폴더의 파일이 존재하는지 여부를 확인합니다. 파일이 존재하지 않는 경우 false를 반환합니다.
  • readFileAssets(filepath:string, encoding?: string): (안드로이드) 안드로이드의 assets 폴더의 하위에 있는 파일을 파일 위치를 통해 읽어온다.
  • copyFileAssets(filepath: string, destPath: string): (안드로이드) 파일을 안드로이드의 assets 폴더 하위로 복사합니다.
  • readDirAssets(dirpath: string): (안드로이드) 파라메터로 전달받은 안드로이드의 assets 폴더 하위의 상대 위치(Relative path)의 내용을 읽는다.
  • scanFile(path: string): (안드로이드) Media Scanner를 이용하여 파일을 스캔(scan)합니다.
  • getAllExternalFilesDirs(): (안드로이드) 모든 공유/외부 스토리의 정보를 반환합니다.
ios 전용 기능
  • copyAssetsFileIOS(imageUri: string, destPath: string, width: number, height: number, scale : number = 1.0, compression : number = 1.0, resizeMode : string = ‘contain’ ): (iOS) iOS의 카메라롤(Camera-roll)에 존재하는 파일을 복사합니다.
  • resumeDownload(jobId: number): (iOS) 전달받은 다운로드 아이디를 이용하여 다운로드를 다시 시작합니다.
  • isResumable(jobId: number): (iOS) 전달받은 다운로드 아이디를 이용하여 다시 다운로드가 가능한지 여부를 확인합니다.
  • completeHandlerIOS(jobId: number): (iOS) 백그라운드에서 다운로드를 진행하는 경우 다운로드가 완료되었음을 알려주도록 설정이 가능합니다.
  • uploadFiles(options: UploadFileOptions): (iOS) 파일을 업르드합니다.
  • stopUpload(jobId: number): (iOS) 파일 업로드를 중지합니다.
  • pathForGroup(groupIdentifier: string): (iOS) iOS에서 com.apple.security.application-groups 설정한 모든 값을 반환합니다.
 

S-park 적용사례

적용사례

MarkerCapture.js

  • 이미지를 만들고 캡쳐해서 file system에 저장하는 코드
import React, { useRef } from 'react' import { Text, ImageBackground, View } from 'react-native' import ViewShot from "react-native-view-shot"; //redux import { useSelector, useDispatch } from 'react-redux' export function SingleCapture({ i }) { const { locations } = useSelector((state) => ({ locations: state.locations, })) const viewShot = useRef(); let payPerHour = locations[i].payPerHour; const focusOnHandler = () => { viewShot.current.capture().then(async (uri) => { console.log(uri); //file system let RNFS = require('react-native-fs'); //linux의 mkdir -p 옵션과 같음. 하위 폴더 없으면 자동생성, 이미 있어도 에러안띄움 await RNFS.mkdir(RNFS.DocumentDirectoryPath + "/PayPerHour"); //document 폴더로 옮김. 이미 있다면 그냥 삭제 const fileName = RNFS.DocumentDirectoryPath + "/PayPerHour/" + payPerHour + ".png"; if (await RNFS.exists(fileName)) await RNFS.unlink(uri); else await RNFS.moveFile(uri, fileName); }) }; return ( <ViewShot key={i} ref={viewShot} options={{ format: 'png' }} style={{ alignItems: 'center', height: 105, width: 140 }}> <ImageBackground source={require("../Assets/pimMarker.png")} style={{ width: 130, height: 100 }} onLoad={focusOnHandler}> <View style={{ alignItems: 'center' }}> <Text style={{ paddingTop: 5, paddingLeft: 10, fontSize: 50 }}> { //%1f 형태로 나타냄 payPerHour % 1000 == 0 ? payPerHour / 1000 + ".0" : payPerHour / 1000 } </Text> </View> </ImageBackground> </ViewShot> ) } export function LoopCapture() { const { locations } = useSelector((state) => ({ locations: state.locations })) let captureViews = []; for (let i = 0; i < locations.length; i++) { captureViews.push(<SingleCapture i={i} key={i} />) } return ( captureViews ); }
notion image
tmp폴더 아래 이미지는 옮겨지거나 삭제되고, PayPerHour 디렉토리에 가격별로 이미지가 저장됨.
 

PMarker.js

  • file system에 저장한 이미지를 가져와서 image 컴포넌트 인자로 넘기는 코드
import React from 'react' import { Marker } from 'react-native-nmap' import { useSelector } from 'react-redux' export function PMarkers({ setModalVisible, setSelectedMarker }) { const { locations } = useSelector((state) => ({ locations: state.locations, })) // console.log("여기는 마커", locations, uridatas); //file system let RNFS = require('react-native-fs'); const Markers = []; for (let i = 0; i < locations.length; i++) { const payPerHour = locations[i].payPerHour; const fileName = RNFS.DocumentDirectoryPath + "/PayPerHour/" + payPerHour + ".png"; Markers.push( <Marker coordinate={{ "longitude": locations[i].longitude, "latitude": locations[i].latitude }} onClick={() => { setModalVisible(true); setSelectedMarker(i); //마커넘버 전달 (db조회번호) } } key={i} image={{ uri: 'file://' + fileName }} width={50} height={50} /> ) } return ( Markers ); }
notion image
uri-data를 바로 사용하던 때와 동일하게 출력되고, 안드로이드에서도 잘 동작한다.