Flutter Templates
Membangun Aplikasi Obrolan Real-Time di Flutter dengan Back4App
35 mnt
pendahuluan membuat aplikasi chat melibatkan pengelolaan data waktu nyata, otentikasi pengguna, penanganan media, dan penyimpanan data yang efisien dalam tutorial ini, anda akan belajar bagaimana membangun aplikasi chat waktu nyata di flutter yang mendukung percakapan satu lawan satu dan grup, status pesan, dan berbagi media kami akan menggunakan back4app—sebagai backend as a service yang didukung oleh parse server—untuk menangani fungsionalitas backend pada akhir tutorial ini, anda akan memiliki aplikasi chat yang sepenuhnya fungsional dengan fitur fitur berikut otentikasi pengguna proses pendaftaran dan login yang aman pesan waktu nyata pengiriman pesan instan menggunakan live queries kehadiran pengguna melacak status online/offline pengguna penyimpanan media mengirim dan menerima gambar dalam chat riwayat pesan menyimpan riwayat chat untuk pengguna prasyarat untuk mengikuti tutorial ini, anda akan membutuhkan flutter sdk terinstal di mesin anda ikuti panduan instalasi flutter resmi https //flutter dev/docs/get started/install pengetahuan dasar tentang flutter dan dart sebuah ide atau editor teks seperti visual studio code atau android studio akun back4app daftar untuk akun gratis di back4app https //www back4app com/ parse server sdk untuk flutter ditambahkan ke proyek anda ikhtisar kami akan membangun aplikasi chat dengan komponen berikut autentikasi pengguna pengguna dapat mendaftar dan masuk daftar kontak menampilkan daftar pengguna untuk diajak chat layar chat antarmuka pesan waktu nyata berbagi media kemampuan untuk mengirim dan menerima gambar status online menampilkan status online/offline pengguna langkah 1 – menyiapkan proyek flutter 1 1 buat proyek flutter baru buka terminal anda dan jalankan flutter create chat app navigasikan ke direktori proyek cd chat app 1 2 tambahkan dependensi buka pubspec yaml dan tambahkan dependensi berikut dependencies flutter sdk flutter parse server sdk flutter ^4 0 1 image picker ^0 8 4+3 cached network image ^3 2 0 uuid ^3 0 4 jalankan flutter pub get untuk menginstal paket parse server sdk flutter berinteraksi dengan back4app image picker pilih gambar dari galeri atau kamera cached network image memuat dan menyimpan gambar secara efisien uuid menghasilkan pengenal unik langkah 2 – menyiapkan back4app 2 1 buat aplikasi back4app baru masuk ke dasbor back4app https //dashboard back4app com/ klik pada "buat aplikasi baru" masukkan nama untuk aplikasi anda, misalnya, "chatapp" , dan klik "buat" 2 2 konfigurasi kelas dan model data kami akan membuat kelas kelas berikut pengguna (kelas parse default) menyimpan informasi pengguna pesan menyimpan pesan obrolan ruangobrolan mewakili obrolan antara pengguna 2 2 1 kelas pengguna bidang username string password string email string isonline boolean avatar file (opsional) kelas user adalah bawaan; kita hanya perlu memastikan bahwa ia memiliki bidang tambahan 2 2 2 kelas pesan bidang pengirim pointer< user> penerima pointer< user> chatroomid string konten string gambar file (opsional) createdat datetime (ditambahkan secara otomatis) 2 2 3 kelas chatroom bidang chatroomid string pengguna array of pointer< user> lastmessage string updatedat datetime (secara otomatis diperbarui) 2 3 dapatkan kredensial aplikasi navigasi ke pengaturan aplikasi > keamanan & kunci catat id aplikasi dan kunci klien langkah 3 – menginisialisasi parse di aplikasi flutter anda buka lib/main dart dan ubah seperti berikut import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'screens/login screen dart'; // you'll create this file next void main() async { widgetsflutterbinding ensureinitialized(); const keyapplicationid = 'your application id'; const keyclientkey = 'your client key'; const keyparseserverurl = 'https //parseapi back4app com'; await parse() initialize( keyapplicationid, keyparseserverurl, clientkey keyclientkey, autosendsessionid true, debug true, ); runapp(myapp()); } class myapp extends statelesswidget { @override widget build(buildcontext context) { return materialapp( title 'chat app', theme themedata( primaryswatch colors blue, ), home loginscreen(), ); } } ganti 'your application id' dan 'your client key' dengan kredensial back4app anda yang sebenarnya langkah 4 – mengimplementasikan autentikasi pengguna 4 1 buat layanan autentikasi buat direktori baru bernama services di bawah lib dan tambahkan file bernama auth service dart // lib/services/auth service dart import 'package\ parse server sdk flutter/parse server sdk dart'; class authservice { future\<parseuser?> signup(string username, string email, string password) async { var user = parseuser(username, password, email); var response = await user signup(); if (response success) { return user; } else { return null; } } future\<parseuser?> login(string username, string password) async { var user = parseuser(username, password, null); var response = await user login(); if (response success) { return user; } else { return null; } } future\<void> logout() async { var user = await parseuser currentuser() as parseuser?; await user? logout(); } future\<parseuser?> getcurrentuser() async { return await parseuser currentuser() as parseuser?; } } 4 2 buat layar login dan pendaftaran buat direktori baru bernama screens di bawah lib dan tambahkan file bernama login screen dart dan signup screen dart }]},{ // lib/screens/login screen dart import 'package\ flutter/material dart'; import ' /services/auth service dart'; import 'home screen dart'; import 'signup screen dart'; class loginscreen extends statelesswidget { final authservice authservice = authservice(); final texteditingcontroller usernamecontroller = texteditingcontroller(); final texteditingcontroller passwordcontroller = texteditingcontroller(); void login(buildcontext context) async { var user = await authservice login( usernamecontroller text trim(), passwordcontroller text trim(), ); if (user != null) { navigator pushreplacement( context, materialpageroute(builder (context) => homescreen()), ); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('login failed'))); } } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('chat app login'), ), body padding( padding const edgeinsets all(16), child column( children \[ textfield( controller usernamecontroller, decoration inputdecoration(labeltext 'username'), ), textfield( controller passwordcontroller, decoration inputdecoration(labeltext 'password'), obscuretext true, ), sizedbox(height 20), elevatedbutton( onpressed () => login(context), child text('login'), ), textbutton( onpressed () => navigator push( context, materialpageroute(builder (context) => signupscreen())), child text('don\\'t have an account? sign up'), ), ], ), ), ); } } 4 2 2 layar pendaftaran // lib/screens/signup screen dart import 'package\ flutter/material dart'; import ' /services/auth service dart'; import 'home screen dart'; class signupscreen extends statelesswidget { final authservice authservice = authservice(); final texteditingcontroller usernamecontroller = texteditingcontroller(); final texteditingcontroller emailcontroller = texteditingcontroller(); final texteditingcontroller passwordcontroller = texteditingcontroller(); void signup(buildcontext context) async { var user = await authservice signup( usernamecontroller text trim(), emailcontroller text trim(), passwordcontroller text trim(), ); if (user != null) { navigator pushreplacement( context, materialpageroute(builder (context) => homescreen()), ); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('sign up failed'))); } } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('chat app sign up'), ), body padding( padding const edgeinsets all(16), child column( children \[ textfield( controller usernamecontroller, decoration inputdecoration(labeltext 'username'), ), textfield( controller emailcontroller, decoration inputdecoration(labeltext 'email'), ), textfield( controller passwordcontroller, decoration inputdecoration(labeltext 'password'), obscuretext true, ), sizedbox(height 20), elevatedbutton( onpressed () => signup(context), child text('sign up'), ), ], ), ), ); } } langkah 5 – mengimplementasikan kehadiran pengguna 5 1 perbarui status online pengguna buat metode di authservice untuk memperbarui status online pengguna // lib/services/auth service dart class authservice { // existing methods future\<void> updateuseronlinestatus(bool isonline) async { var user = await parseuser currentuser() as parseuser?; if (user != null) { user set('isonline', isonline); await user save(); } } } 5 2 atur status online saat masuk dan keluar perbarui metode masuk dan keluar // lib/services/auth service dart class authservice { // existing methods future\<parseuser?> login(string username, string password) async { var user = parseuser(username, password, null); var response = await user login(); if (response success) { await updateuseronlinestatus(true); return user; } else { return null; } } future\<void> logout() async { await updateuseronlinestatus(false); var user = await parseuser currentuser() as parseuser?; await user? logout(); } } langkah 6 – menampilkan daftar kontak 6 1 buat layanan pengguna buat user service dart di bawah services // lib/services/user service dart import 'package\ parse server sdk flutter/parse server sdk dart'; class userservice { future\<list\<parseuser>> getallusers() async { final querybuilder\<parseuser> queryusers = querybuilder\<parseuser>(parseuser forquery()); final parseresponse apiresponse = await queryusers query(); if (apiresponse success && apiresponse results != null) { return apiresponse results as list\<parseuser>; } else { return \[]; } } } 6 2 buat layar utama // lib/screens/home screen dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import ' /services/user service dart'; import ' /services/auth service dart'; import 'chat screen dart'; class homescreen extends statefulwidget { @override homescreenstate createstate() => homescreenstate(); } class homescreenstate extends state\<homescreen> { final userservice userservice = userservice(); final authservice authservice = authservice(); list\<parseuser> users = \[]; parseuser? currentuser; @override void initstate() { super initstate(); fetchusers(); getcurrentuser(); } void getcurrentuser() async { currentuser = await authservice getcurrentuser(); } void fetchusers() async { var allusers = await userservice getallusers(); setstate(() { users = allusers where((user) => user username != currentuser? username) tolist(); }); } void logout(buildcontext context) async { await authservice logout(); navigator pushreplacementnamed(context, '/'); } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('contacts'), actions \[ iconbutton(onpressed () => logout(context), icon icon(icons logout)), ], ), body listview\ builder( itemcount users length, itembuilder (context, index) { var user = users\[index]; return listtile( title text(user username ?? ''), subtitle text(user get('isonline') == true ? 'online' 'offline'), ontap () { navigator push( context, materialpageroute(builder (context) => chatscreen(receiver user)), ); }, ); }, ), ); } } langkah 7 – mengimplementasikan pesan real time dengan live queries 7 1 siapkan klien live query tambahkan ketergantungan berikut di pubspec yaml dependencies flutter sdk flutter parse server sdk flutter git url https //github com/parse community/parse sdk flutter git ref master ini memastikan anda memiliki versi terbaru dengan dukungan live query 7 2 inisialisasi live query di main dart // lib/main dart void main() async { widgetsflutterbinding ensureinitialized(); const keyapplicationid = 'your application id'; const keyclientkey = 'your client key'; const keyparseserverurl = 'https //parseapi back4app com'; const livequeryurl = 'wss\ //your app back4app io'; await parse() initialize( keyapplicationid, keyparseserverurl, clientkey keyclientkey, autosendsessionid true, debug true, livequeryurl livequeryurl, ); runapp(myapp()); } ganti 'your app' dengan subdomain aplikasi back4app anda 7 3 buat layar obrolan // lib/screens/chat screen dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'package\ uuid/uuid dart'; import 'package\ image picker/image picker dart'; import ' /services/auth service dart'; import 'package\ cached network image/cached network image dart'; class chatscreen extends statefulwidget { final parseuser receiver; chatscreen({required this receiver}); @override chatscreenstate createstate() => chatscreenstate(); } class chatscreenstate extends state\<chatscreen> { final authservice authservice = authservice(); parseuser? currentuser; list\<parseobject> messages = \[]; string chatroomid = ''; final texteditingcontroller messagecontroller = texteditingcontroller(); late parselivelist\<parseobject> livemessages; @override void initstate() { super initstate(); getcurrentuser(); setupchatroom(); } void getcurrentuser() async { currentuser = await authservice getcurrentuser(); if (currentuser != null) { setuplivequery(); } } void setupchatroom() { string userid = currentuser! objectid!; string receiverid = widget receiver objectid!; chatroomid = userid compareto(receiverid) > 0 ? '$userid $receiverid' '$receiverid $userid'; } void setuplivequery() { querybuilder\<parseobject> querymessages = querybuilder\<parseobject>(parseobject('message')) whereequalto('chatroomid', chatroomid) orderbyascending('createdat'); livemessages = parselivelist\<parseobject>( querymessages, listeningincludes \['sender'], lazyloading false, ); setstate(() {}); } void sendmessage({string? content, parsefilebase? imagefile}) async { var message = parseobject('message') set('sender', currentuser) set('receiver', widget receiver) set('chatroomid', chatroomid) set('content', content ?? '') set('image', imagefile); await message save(); messagecontroller clear(); } void pickimage() async { final picker = imagepicker(); final pickedfile = await picker pickimage(source imagesource gallery, imagequality 50); if (pickedfile != null) { var file = parsefile(file(pickedfile path)); await file save(); sendmessage(imagefile file); } } @override void dispose() { livemessages dispose(); super dispose(); } @override widget build(buildcontext context) { if (currentuser == null || livemessages == null) { return scaffold( appbar appbar( title text('chat with ${widget receiver username}'), ), body center(child circularprogressindicator()), ); } return scaffold( appbar appbar( title text('chat with ${widget receiver username}'), ), body column( children \[ expanded( child parselivelistwidget\<parseobject>( query livemessages, reverse false, lazyloading false, childbuilder (context, snapshot) { if (snapshot failed) { return text('error ${snapshot error}'); } else if (snapshot hasdata) { var message = snapshot loadeddata!; var sender = message get\<parseuser>('sender')!; var isme = sender objectid == currentuser! objectid; var content = message get\<string>('content') ?? ''; var image = message get\<parsefilebase>('image'); return align( alignment isme ? alignment centerright alignment centerleft, child container( padding edgeinsets all(8), margin edgeinsets all(8), decoration boxdecoration( color isme ? colors blue\[100] colors grey\[300], borderradius borderradius circular(8), ), child column( crossaxisalignment crossaxisalignment start, children \[ if (content isnotempty) text(content), if (image != null) cachednetworkimage( imageurl image url!, placeholder (context, url) => circularprogressindicator(), errorwidget (context, url, error) => icon(icons error), ), ], ), ), ); } else { return container(); } }, ), ), divider(height 1), container( padding edgeinsets symmetric(horizontal 8), color colors white, child row( children \[ iconbutton( icon icon(icons photo), onpressed pickimage, ), expanded( child textfield( controller messagecontroller, decoration inputdecoration collapsed(hinttext 'type a message'), ), ), iconbutton( icon icon(icons send), onpressed () { if ( messagecontroller text trim() isnotempty) { sendmessage(content messagecontroller text trim()); } }, ), ], ), ), ], ), ); } } penjelasan parselivelistwidget sebuah widget yang mendengarkan pembaruan kueri langsung dan membangun kembali saat data berubah sendmessage() mengirim pesan teks atau gambar pickimage() menggunakan image picker untuk memilih gambar dan mengirimkannya sebagai pesan setuplivequery() mengatur kueri langsung untuk mendengarkan pesan baru di ruang obrolan langkah 8 – menguji aplikasi 8 1 jalankan aplikasi di terminal anda, jalankan flutter run 8 2 uji pesan buka aplikasi di dua perangkat atau emulator daftar atau masuk dengan akun pengguna yang berbeda dari satu akun, pilih pengguna lain dari daftar kontak kirim pesan dan gambar; mereka harus muncul secara real time di kedua perangkat kesimpulan selamat! anda telah membangun aplikasi obrolan real time di flutter menggunakan back4app aplikasi ini mendukung autentikasi pengguna masuk dan daftar yang aman pesan real time pembaruan instan menggunakan live queries kehadiran pengguna pelacakan status online/offline berbagi media mengirim dan menerima gambar riwayat pesan menyimpan pesan obrolan langkah selanjutnya obrolan grup perluas aplikasi untuk mendukung percakapan grup status pesan implementasikan tanda terima baca dan indikator mengetik notifikasi push kirim notifikasi untuk pesan baru saat aplikasi berada di latar belakang foto profil izinkan pengguna untuk mengunggah avatar peningkatan keamanan amankan data dengan acl dan izin berbasis peran sumber daya tambahan dokumentasi back4app https //www back4app com/docs panduan parse sdk untuk flutter https //docs parseplatform org/flutter/guide/ dokumentasi resmi flutter https //flutter dev/docs parse live query https //docs parseplatform org/js/guide/#live queries selamat berkoding!