Flutter : Upload File Menggunakan File Picker

Flutter : Upload File Menggunakan File Picker

Sobatcoding.com - Tutorial cara upload menggunakan File Picker flutter dan REST API

Halo sobat coding. Kali ini kita akan coba belajar upload file menggunakan File Picker Flutter dengan REST API. Bagaimana caranya? Kita langsung coba praktekan langkah-langkahnya seperti berikut:

 

Install Dependencies Package

Ada beberapa requirement package flutter yang admin gunakan

http: ^0.13.4
shared_preferences: ^2.0.11
font_awesome_flutter: ^10.1.0
file_picker: ^3.0.4
intl: ^0.17.0

Buka file pubspec.yaml dan silahkan copy dependencies di atas kemudian jalankan command untuk install package di atas

flutter pub get

 

Membuat View Dart Upload

Selanjutnya kita buat file upload_view.dart di folder lib\views, kemudian buat beberapa widget untuk textbox nama file, textbox tanggal file dan tombol untuk browse file.

@override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("Test Upload File"),
        ),
        body: Form(
            key: _formKey,
            child: ListView(children: <Widget>[
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextFormField(
                    key: Key(txtNama),
                    validator: (String? value) {
                      if (value == null || value.isEmpty) {
                        return 'Nama file harus diisi';
                      } else {
                        return null;
                      }
                    },
                    controller: txtEditNama,
                    onSaved: (String? val) {
                      txtEditNama.text = val!;
                    },
                    decoration: const InputDecoration(
                      filled: true,
                      fillColor: Colors.white,
                      border: OutlineInputBorder(
                          borderRadius: BorderRadius.all(
                            Radius.circular(5.0),
                          ),
                          borderSide:
                              BorderSide(color: Colors.white, width: 2)),
                      hintText: 'Nama file',
                      contentPadding: EdgeInsets.all(10.0),
                    ),
                    style: const TextStyle(fontSize: 16.0)),
              ),
              const Padding(
                padding: EdgeInsets.all(8.0),
                child: Text("Nama File", style: TextStyle(fontSize: 16.0)),
              ),
              buildDatePicker(context),
              const Padding(
                padding: EdgeInsets.all(8.0),
                child: Text("Browse File", style: TextStyle(fontSize: 16.0)),
              ),
              buildFilePicker(),
              Container(
              padding: const EdgeInsets.all(8.0),
              margin: const EdgeInsets.only(bottom: 10),
              child: ElevatedButton.icon(
                icon: const Icon(
                  Icons.send,
                  color: Colors.white,
                  size: 32.0,
                ),
                label: const Text('SIMPAN',
                    style: TextStyle(fontSize: 18.0)),
                onPressed: () {
                  _validateInputs();
                },
                style: ElevatedButton.styleFrom(
                  primary: Colors.lightBlue,
                  minimumSize: const Size(115, 55),
                  maximumSize: const Size(115, 55),
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(5.0),
                  ),
                ),
              ),
            )
            ])));
  }

//membuat input date picker
Widget buildDatePicker(context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Row(
        children: [
          Expanded(
            child: TextFormField(
                readOnly: true,
                controller: txtDate,
                validator: (String? value) {
                  if (value == null || value.isEmpty) {
                    return 'Tanggal harus diisi';
                  } else {
                    return null;
                  }
                },
                decoration: const InputDecoration(
                  filled: true,
                  fillColor: Colors.white,
                  border: OutlineInputBorder(
                      borderRadius: BorderRadius.all(
                        Radius.circular(5.0),
                      ),
                      borderSide: BorderSide(color: Colors.white, width: 2)),
                  hintText: 'Tanggal File',
                  contentPadding: EdgeInsets.all(10.0),
                ),
                style: const TextStyle(fontSize: 16.0)),
          ),
          const SizedBox(width: 5),
          ElevatedButton(
              style: ElevatedButton.styleFrom(
                  primary: Colors.lightBlue,
                  minimumSize: const Size(70, 48),
                  maximumSize: const Size(70, 48)),
              onPressed: () => pickDatePicker(context),
              child: const FaIcon(
                FontAwesomeIcons.calendarDay,
                color: Colors.white,
                size: 24.0,
              ))
        ],
      ),
    );
  }

//membuat input browse file
Widget buildFilePicker() {
    return Padding(
      padding: const EdgeInsets.all(8),
      child: Row(
        children: [
          Expanded(
            child: TextFormField(
                readOnly: true,
                validator: (String? value) {
                  if (value == null || value.isEmpty) {
                    return 'File harus diupload';
                  } else {
                    return null;
                  }
                },
                controller: txtFilePicker,
                decoration: const InputDecoration(
                  filled: true,
                  fillColor: Colors.white,
                  border: OutlineInputBorder(
                      borderRadius: BorderRadius.all(
                        Radius.circular(5.0),
                      ),
                      borderSide: BorderSide(color: Colors.white, width: 2)),
                  hintText: 'Upload File',
                  contentPadding: EdgeInsets.all(10.0),
                ),
                style: const TextStyle(fontSize: 16.0)),
          ),
          const SizedBox(width: 5),
          ElevatedButton.icon(
            icon: const Icon(
              Icons.upload_file,
              color: Colors.white,
              size: 24.0,
            ),
            label: const Text('Pilih File', style: TextStyle(fontSize: 16.0)),
            onPressed: () {
              selectFile();
            },
            style: ElevatedButton.styleFrom(
              primary: Colors.lightBlue,
              minimumSize: const Size(122, 48),
              maximumSize: const Size(122, 48),
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(5.0),
              ),
            ),
          ),
        ],
      ),
    );
  }

 

selanjutnya kita buat beberapa function

//fungsi untuk menampilkan date picker
Future pickDatePicker(BuildContext context) async {
    final newDatePicker = await showDatePicker(
        context: context,
        firstDate: DateTime(DateTime.now().year),
        lastDate: DateTime(DateTime.now().year + 5),
        initialDate: date,
        builder: (context, child) {
          return Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Align(
                alignment: Alignment.center,
                child: ConstrainedBox(
                  constraints:
                      const BoxConstraints(maxWidth: 400.0, maxHeight: 520.0),
                  child: child,
                ),
              )
            ],
          );
        });

    if (newDatePicker == null) return;

    setState(() {
      //
      String rawDate = newDatePicker.toString();
      var explode = rawDate.split(" ");
      String tgl = convertDateFromString(explode[0]).toString();
      txtDate.text = tgl;
    });
  }

//fungsi untuk select file
selectFile() async {
    FilePickerResult? result = await FilePicker.platform
        .pickFiles(type: FileType.custom, allowedExtensions: ['pdf']);
    if (result != null) {
      setState(() {
        txtFilePicker.text = result.files.single.name;
        filePickerVal = File(result.files.single.path.toString());
      });
    } else {
      // User canceled the picker
    }
  }

//fungsi untuk validasi dan simpan
void _validateInputs() {
    if (_formKey.currentState!.validate()) {
      //If all data are correct then save data to out variables
      _formKey.currentState!.save();
      simpan();
    }
  }

simpan() async {

    final String nama = txtEditNama.text; //txtNama;
    var rawTgl = txtDate.text.split("/");
    var yM = rawTgl[2];
    var mM = rawTgl[1];
    var dM = rawTgl[0];
    final String tgl = yM + "-" + mM + "-" + dM;
    
    try {
      //post date
      Map<String, String> headers = {
        'Content-Type': 'application/json; charset=UTF-8',
      };
      var request = http.MultipartRequest('POST', Uri.parse('https://api.sobatcoding.com/testing/upload'));

      request.headers.addAll(headers);
      request.fields['nama'] = nama;
      request.fields['tgl'] = tgl;
      
      request.files.add(http.MultipartFile('file',
          filePickerVal!.readAsBytes().asStream(), filePickerVal!.lengthSync(),
          filename: filePickerVal!.path.split("/").last));

      var res = await request.send();
      var responseBytes = await res.stream.toBytes();
      var responseString = utf8.decode(responseBytes);

      //debug
      debugPrint("response code: " + res.statusCode.toString());
      debugPrint("response: " + responseString.toString());

      final dataDecode = jsonDecode(responseString);
      debugPrint(dataDecode.toString());

      if (res.statusCode == 200) {

        return showDialog<void>(
          context: context,
          barrierDismissible: false, // user must tap button!
          builder: (BuildContext context) {
            return AlertDialog(
              title: const Text('Informasi'),
              content: SingleChildScrollView(
                child: ListBody(
                  children: const <Widget>[
                    Text(
                        "File berhasil diupload"),
                  ],
                ),
              ),
              actions: [
                TextButton(
                  child: const Text('OK'),
                  onPressed: () {
                    //
                    Navigator.of(context, rootNavigator: false).pop();
                  },
                ),
              ],
            );
          },
        );
      } else {
       
      }
    } catch (e) {
      debugPrint('$e');
      
    }
  }

 

Hasil dari script di atas adalah seperti berikut

form upload flutter

Untuk debuging bisa kita lihat di terminal visual studio seperti berikut

debug

 

Untuk URL REST API bisa kalian ganti dengan URL kalian masing-masing. Kalian bisa menggunakan REST Full API Laravel atau REST Full API Codeigniter. Berikut contoh sederhana untuk REST API di atas.

//NATIVE PHP
$data = [
 'nama' => $_POST['nama'],
 'tgl' => $_POST['tgl'],
 'file' => $_FILES['file']['name'],
];

header('Content-Type: application/json');
echo json_encode($data, JSON_PRETTY_PRINT);

//Laravel
$file = $request->file('file');
$data = [
                'nama' => $request->get('nama'),
                'tgl'  => $request->get('tgl'),
                'file' => $file->getClientOriginalName()
            ];
return response()->json(['success' => true, 'data' => $data]);

 

Untuk lebih lengkapnya bisa kalian cek source code di link berikut : https://github.com/sobatcoding21/AndroidFlutter/blob/main/lib/views/upload_view.dart.

 

Sekian tutorial kali ini. Jika teman-teman memiliki pertanyaan atau saran mengenai artikel ini, jangan ragu untuk meninggalkan komentar pada form di bawah ini.

Semoga bermanfaat.