【ReactNative】Androidでbase64画像の保存とPOST送信

AndroidのReactNativeアプリでbase64画像の保存とPOST送信をします。

# 画像の保存
## iOSでの保存、もしくはAndroidでhttp or httpsリソースの画像の保存(base64だとエラー)の場合
まずはbase64でない場合。
以下で画像のダウンロードができます。
一度FileSystemに画像をダウンロードして、そのURIを使っています。

```jsx:DowloadImage.jsx

import * as FileSystem from 'expo-file-system';
import * as MediaLibrary from 'expo-media-library';
import * as Permissions from 'expo-permissions';

const downloadImage=( file )=>{
    FileSystem.downloadAsync(
        file.uri,
        FileSystem.documentDirectory + 'image.jpeg'
    )
        .then( async ( { uri } ) => {
            const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL );
            if( status !== 'granted' ) return
            CameraRoll.saveToCameraRoll( uri, "photo" );
            MediaLibrary.saveToLibraryAsync( uri )
         })
}

```

## Androidでbase64画像の保存の場合
Androidで、FileSystemでbase64画像を読み込むと、URLスキームがhttpかhttpsじゃないとダメですって怒られます。
ので、以下で保存します。

```jsx:DowloadBase64Image.jsx

import * as FileSystem from 'expo-file-system';
import * as MediaLibrary from 'expo-media-library';
import * as Permissions from 'expo-permissions';

const downloadImage=( file )=>{
    const dataUri = file.uri
    const tempFileDirectory = `${ FileSystem.cacheDirectory }uploadTmp`
    
    // 一時保存用のディレクトリを作る
    await FileSystem.makeDirectoryAsync( tempFileDirectory, { intermediates: true } ) 

    // 一時保存用のファイルを作る
    const tempFilePath = `${ tempFileDirectory }${ Date.now() }.jpeg`

    // データの中身を取り出す
    const base64EncodedData = dataUri.split( ',' )[ 1 ]

    // base64として、作ったファイルに書き込む
    await FileSystem.writeAsStringAsync( tempFilePath, base64EncodedData, {
            encoding: FileSystem.EncodingType.Base64,
        } )

    // そのファイルのパスをURIに、同様にカメラロールに保存
    const uri = tempFilePath
    const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL );
    if( status !== 'granted' ) return
    CameraRoll.saveToCameraRoll( uri, "photo" );
    MediaLibrary.saveToLibraryAsync( uri )

    // 一時的に作っていただけなので、ファイルを消す
    await FileSystem.deleteAsync( tempFilePath )                   
} 

```

Androidだと、ReactNativeのライブラリではFileSystemにそのままbase64はダウンロードできないので、自分でファイル作って書き込んで、それのURIを使っています。

# POST送信
AndroidでAxiosを使って、base64画像を送信しようとすると、Network Errorが出ます。
これも、以下で送信可能です(ほぼ上記の保存と同じ)。

```jsx:PostBase64Image.jsx

import * as FileSystem from 'expo-file-system';
import * as MediaLibrary from 'expo-media-library';
import * as Permissions from 'expo-permissions';
import axios from 'axios'

const postImage=( file )=>{

    // 画像の保存と同様にFileSystemにファイルを作って書き込む
    const dataUri = file.uri
    const tempFileDirectory = `${ FileSystem.cacheDirectory }uploadTmp`
    toryAsync( tempFileDirectory, { intermediates: true } ) 
    const tempFilePath = `${ tempFileDirectory }${ Date.now() }.jpeg`
    const base64EncodedData = dataUri.split( ',' )[ 1 ]
    await FileSystem.writeAsStringAsync( tempFilePath, base64EncodedData, {
            encoding: FileSystem.EncodingType.Base64,
        } )

    const uri = tempFilePath
    // そのファイルのパスを、送るファイルのURIに指定
    const file = {
	    uri:uri,
	    type: "image/jpeg",
	    name: "file.jpeg",
	}
    const formData = new FormData()
    formData.append( "file", file )
    await axios.post( URL, data)
        .then( async () =>{ 
            // 一時的に作っていただけなので、ファイルを消す
            await FileSystem.deleteAsync( tempFilePath ) 
        })                  
} 

```

# 参考

[[Android] FormData does not support data URIs](https://gitmemory.com/issue/facebook/react-native/25790/548347384)