🖌️

【Flutter】file_pickerのライブラリを使用して画像のアップロードを実装

2023/02/06に公開

概要

Flutterでファイルのアップロード機能を実装するとなると、いくつか実装の選択肢があると思います。
少し調べた結果、file_pickerというライブラリが、複数のプラットフォーム(iOSやWebなど)に対応して良さそうでした。今回これを使って、画像のアップロードの実装メモを残しておきます。

前提

  • 使用したFlutterのバージョンは3.3.10です。
  • 使用したfile_pickerのバージョンは5.2.5です。
  • Webで動作確認を行っています。

実装サンプル

まずはファイルの選択部分の実装です。選択したファイルをstateに格納します。

class SampleUploadWidget extends StatefulHookConsumerWidget {
  const SampleUploadWidget({super.key});

  
  SampleUploadState createState() => SampleUploadState();
}

class SampleUploadState extends ConsumerState<SampleUploadWidget> {
  final _formKey = GlobalKey<FormState>();

  
  Widget build(BuildContext context) {
    // 選択したファイルを格納するstate
    final imageFileState = useState<PlatformFile?>(null);

    Future<void> selectImage() async {
      // file_pickerのライブラリを使用してファイルを取得
      var result = await FilePicker.platform.pickFiles();
      if (result != null) {
        imageFileState.value = result.files.first;
      } else {
        // User canceled the picker
      }
    }

    Future<void> uploadFile() async {
      // ファイルをAPIで送信する処理(ソースの内容は後述)
      if (imageFileState.value != null) {
        var res = await UploadApiService.uploadFile(imageFileState.value);
      }
    }

    return Center(
      child: Form(
        key: _formKey,
        child: Column(
          children: [
            // ファイルを選択した場合はImageを表示
            if (imageFileState.value != null)
              Column(children: [
                SizedBox(
                    width: 150,
                    height: 150,
                    child: Image.memory(imageFileState.value!.bytes!)),
                const SizedBox(height: 20),
              ]),
            ElevatedButton(
              onPressed: () async => {
                // ファイルの選択処理
                selectImage()
              },
              style: ElevatedButton.styleFrom(
                fixedSize: const Size(250, 50),
                backgroundColor: const Color.fromARGB(255, 102, 100, 100),
              ),
              child: const Text('ファイル選択'),
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () async => {
                // アップロード処理
                await uploadFile()
              },
              style: ElevatedButton.styleFrom(fixedSize: const Size(250, 50)),
              child: const Text('アップロード'),
            ),
          ],
        ),
      ),
    );
  }
}

次は選択したファイルをAPIでPOST送信する処理です。
FlutterのFileとXFileとの違いの記事を参考にして、ファイルをバイト形式にしてMultipartFile.fromBytesを使用して送信します。

class UploadApiService {
  static Future<Response> uploadFile(PlatformFile fileResult) async {
    var url = Uri.parse("${dotenv.get('API_URL')}/fileUpload");
    var request = http.MultipartRequest(
      "POST",
      url,
    );

    // ファイル項目を追加
    var multipartFile = http.MultipartFile.fromBytes(
          "sampleFile", fileResult.bytes!, filename: fileResult.name);
    request.files.add(multipartFile);
    // Post送信
    var streamedResponse = await request.send();
    var response = await http.Response.fromStream(streamedResponse);
    return response;
  }
}

Discussion