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:
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
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
Untuk debuging bisa kita lihat di terminal visual studio seperti berikut
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.
Komentar 2