子供と一緒に遊べる『シルエットクイズ』アプリをつくっています。単純に画像を切り替えるだけのアプリですが、画像をサーバーにアップロードすることなく登録したく、その方法について調査した結果をメモしておきます。
- expo version "42.0.3"
- react-native version "0.63.2"
expo-file-system
を使う
Expoで提供されているexpo-file-system
を使うとデバイスのファイルシステムにアクセスできます。これを使って実装してみました。
expo-file-system
で作成できるディレクトリは2種類あり、用途に合わせて使い分けが必要です。
- FileSystem.documentDirectory:アプリによって明示的に削除するまで残る
- FileSystem.cacheDirectory:保存容量が少なくなるとシステムによって自動的に削除される
カメラロールから画像を選んでFileSystemに保存するコード
実際に実装したコードから抜粋したものですが、雰囲気は伝わると思います。ポイントは FileSystem.makeDirectoryAsync
でディレクトリを作成する点と、FileSystem.copyAsync
で画像を保存する点です。
import * as FileSystem from 'expo-file-system' import * as ImagePicker from 'expo-image-picker' import React, { useState, useEffect } from 'react' import { View, Image } from 'react-native' export default function () { const tempDir = FileSystem.cacheDirectory + 'silhouette-quiz/' const [questionImage, setQuestionImage] = useState() useEffect(() => { FileSystem.getInfoAsync(tempDir).then((dirInfo) => { if (!dirInfo.exists) { // tempDirが無ければ作成する FileSystem.makeDirectoryAsync(documentDir, { intermediates: true }) } }) if (Platform.OS !== 'web') { ImagePicker.requestMediaLibraryPermissionsAsync().then((status) => { if (!status.granted) { alert('Sorry, we need camera roll permissions to make this work!') } }) } }, []) const handleClickQuestionImagePickButton = async () => { const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, allowsEditing: true, aspect: [4, 3], quality: 1, }) if (!result.cancelled) { // カメラロールから選択した画像をファイルシステムに保存する const to = tempDir + 'question_image' await FileSystem.copyAsync({ from: result.uri, to, }) setQuestionImage(to) } } return ( <View> <Image source={{ uri: questionImage }} /> </View> ) }