Flutter Templates
สร้างแอปพ chat แบบเรียลไทม์ใน Flutter ด้วย Back4App
34 นาที
บทนำ การสร้างแอปพลิเคชันแชทเกี่ยวข้องกับการจัดการข้อมูลเรียลไทม์ การตรวจสอบสิทธิ์ผู้ใช้ การจัดการสื่อ และการจัดเก็บข้อมูลอย่างมีประสิทธิภาพ ในบทเรียนนี้ คุณจะได้เรียนรู้วิธีการสร้างแอปพลิเคชันแชทเรียลไทม์ใน flutter ที่รองรับการสนทนาแบบหนึ่งต่อหนึ่งและกลุ่ม สถานะข้อความ และการแชร์สื่อ เราจะใช้ back4app ซึ่งเป็นบริการด้านหลังที่ขับเคลื่อนโดย parse server เพื่อจัดการฟังก์ชันการทำงานด้านหลัง เมื่อสิ้นสุดบทเรียนนี้ คุณจะมีแอปแชทที่ใช้งานได้อย่างสมบูรณ์พร้อมฟีเจอร์ดังต่อไปนี้ การตรวจสอบสิทธิ์ผู้ใช้ กระบวนการลงทะเบียนและเข้าสู่ระบบที่ปลอดภัย การส่งข้อความเรียลไทม์ การส่งข้อความทันทีโดยใช้ live queries สถานะผู้ใช้ การติดตามสถานะออนไลน์/ออฟไลน์ของผู้ใช้ การจัดเก็บสื่อ การส่งและรับภาพในแชท ประวัติข้อความ การเก็บรักษาประวัติการแชทสำหรับผู้ใช้ ข้อกำหนดเบื้องต้น เพื่อที่จะติดตามบทเรียนนี้ คุณจะต้องมี flutter sdk ติดตั้งบนเครื่องของคุณ ทำตาม คู่มือการติดตั้ง flutter อย่างเป็นทางการ https //flutter dev/docs/get started/install ความรู้พื้นฐานเกี่ยวกับ flutter และ dart ide หรือโปรแกรมแก้ไขข้อความ เช่น visual studio code หรือ android studio บัญชี back4app ลงทะเบียนสำหรับบัญชีฟรีที่ back4app https //www back4app com/ parse server sdk สำหรับ flutter เพิ่มเข้าไปในโปรเจกต์ของคุณ ภาพรวม เราจะสร้างแอปพลิเคชันแชทด้วยส่วนประกอบต่อไปนี้ การตรวจสอบสิทธิ์ผู้ใช้ ผู้ใช้สามารถลงทะเบียนและเข้าสู่ระบบ รายชื่อผู้ติดต่อ แสดงรายชื่อผู้ใช้ที่สามารถแชทด้วย หน้าจอแชท อินเทอร์เฟซการส่งข้อความแบบเรียลไทม์ การแชร์สื่อ ความสามารถในการส่งและรับภาพ สถานะออนไลน์ แสดงสถานะออนไลน์/ออฟไลน์ของผู้ใช้ ขั้นตอนที่ 1 – การตั้งค่าโปรเจกต์ flutter 1 1 สร้างโปรเจกต์ flutter ใหม่ เปิดเทอร์มินัลของคุณและรัน flutter create chat app ไปที่ไดเรกทอรีของโปรเจกต์ cd chat app 1 2 เพิ่ม dependencies เปิด pubspec yaml และเพิ่ม dependencies ต่อไปนี้ 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 รัน flutter pub get เพื่อติดตั้งแพ็กเกจ parse server sdk flutter ติดต่อกับ back4app image picker เลือกรูปภาพจากแกลเลอรีหรือกล้อง cached network image โหลดและแคชภาพอย่างมีประสิทธิภาพ uuid สร้างตัวระบุที่ไม่ซ้ำกัน ขั้นตอนที่ 2 – การตั้งค่า back4app 2 1 สร้างแอปพลิเคชัน back4app ใหม่ เข้าสู่ระบบที่ แดชบอร์ด back4app https //dashboard back4app com/ คลิกที่ "สร้างแอปใหม่" ใส่ชื่อสำหรับแอปพลิเคชันของคุณ เช่น "chatapp" , และคลิก "สร้าง" 2 2 กำหนดค่าชั้นเรียนและโมเดลข้อมูล เราจะสร้างชั้นเรียนต่อไปนี้ ผู้ใช้ (ชั้นเรียน parse เริ่มต้น) เก็บข้อมูลผู้ใช้ ข้อความ เก็บข้อความแชท ห้องแชท แสดงถึงการแชทระหว่างผู้ใช้ 2 2 1 ชั้นเรียนผู้ใช้ ฟิลด์ ชื่อผู้ใช้ string รหัสผ่าน string อีเมล string ออนไลน์อยู่ boolean อวตาร file (optional) ฟิลด์ chatroomid สตริง ผู้ใช้ อาร์เรย์ของ pointer< user> lastmessage สตริง updatedat datetime (อัปเดตโดยอัตโนมัติ) 2 3 รับข้อมูลประจำตัวของแอปพลิเคชัน ไปที่ การตั้งค่าแอป > ความปลอดภัย & คีย์ จดบันทึก application id และ client key ขั้นตอนที่ 3 – เริ่มต้น parse ในแอป flutter ของคุณ เปิด lib/main dart และแก้ไขตามนี้ 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(), ); } } แทนที่ 'your application id' และ 'your client key' ด้วยข้อมูลรับรอง back4app ที่แท้จริงของคุณ ขั้นตอนที่ 4 – การดำเนินการตรวจสอบสิทธิผู้ใช้ 4 1 สร้างบริการการตรวจสอบสิทธิ สร้างไดเรกทอรีใหม่ชื่อ services ภายใต้ lib และเพิ่มไฟล์ชื่อ 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 สร้างหน้าล็อกอินและลงทะเบียน สร้างไดเรกทอรีใหม่ชื่อ screens ภายใต้ lib และเพิ่มไฟล์ชื่อ login screen dart และ signup screen dart 4 2 1 หน้าล็อกอิน // 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 หน้าลงทะเบียน // 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'), ), ], ), ), ); } } ขั้นตอนที่ 5 – การดำเนินการเกี่ยวกับสถานะผู้ใช้ 5 1 อัปเดตสถานะออนไลน์ของผู้ใช้ สร้างวิธีการใน authservice เพื่ออัปเดตสถานะออนไลน์ของผู้ใช้ // 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 ตั้งค่าสถานะออนไลน์เมื่อเข้าสู่ระบบและออกจากระบบ อัปเดตวิธีการเข้าสู่ระบบและออกจากระบบ // 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(); } } ขั้นตอนที่ 6 – แสดงรายการติดต่อ 6 1 สร้างบริการผู้ใช้ สร้าง user service dart ภายใต้ 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 สร้างหน้าหลัก // 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)), ); }, ); }, ), ); } } ขั้นตอนที่ 7 – การนำเสนอการส่งข้อความแบบเรียลไทม์ด้วย live queries 7 1 ตั้งค่าลูกค้า live query เพิ่มการพึ่งพาต่อไปนี้ใน pubspec yaml dependencies flutter sdk flutter parse server sdk flutter git url https //github com/parse community/parse sdk flutter git ref master นี่ทำให้คุณมีเวอร์ชันล่าสุดที่รองรับ live query 7 2 เริ่มต้น live query ใน 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()); } unhandled content type this is an additional text that needs translation แทนที่ 'your app' ด้วยซับโดเมนแอปพลิเคชัน back4app ของคุณ 7 3 สร้างหน้าจอแชท // 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()); } }, ), ], ), ), ], ), ); } } คำอธิบาย parselivelistwidget วิดเจ็ตที่ฟังการอัปเดตการค้นหาสดและสร้างใหม่เมื่อข้อมูลเปลี่ยนแปลง sendmessage() ส่งข้อความหรือภาพ pickimage() ใช้ image picker เพื่อเลือกภาพและส่งเป็นข้อความ setuplivequery() ตั้งค่าการค้นหาสดเพื่อติดตามข้อความใหม่ในห้องแชท ขั้นตอนที่ 8 – การทดสอบแอป 8 1 เรียกใช้แอป ในเทอร์มินัลของคุณ ให้รัน flutter run 8 2 การทดสอบการส่งข้อความ เปิดแอปบนอุปกรณ์หรืออีมูเลเตอร์สองเครื่อง ลงทะเบียนหรือเข้าสู่ระบบด้วยบัญชีผู้ใช้ที่แตกต่างกัน จากบัญชีหนึ่ง ให้เลือกผู้ใช้คนอื่นจากรายชื่อผู้ติดต่อ ส่งข้อความและภาพ; ควรปรากฏในเวลาจริงบนทั้งสองอุปกรณ์ บทสรุป ขอแสดงความยินดี! คุณได้สร้างแอปพลิเคชันแชทแบบเรียลไทม์ใน flutter โดยใช้ back4app แอปนี้รองรับ การตรวจสอบผู้ใช้ การเข้าสู่ระบบและการลงทะเบียนที่ปลอดภัย การส่งข้อความแบบเรียลไทม์ การอัปเดตทันทีโดยใช้ live queries สถานะผู้ใช้ การติดตามสถานะออนไลน์/ออฟไลน์ การแชร์สื่อ การส่งและรับภาพ ประวัติข้อความ การเก็บรักษาข้อความแชท ขั้นตอนถัดไป การสนทนากลุ่ม ขยายแอปเพื่อรองรับการสนทนากลุ่ม สถานะข้อความ นำการอ่านและการพิมพ์มาใช้ การแจ้งเตือนแบบพุช ส่งการแจ้งเตือนสำหรับข้อความใหม่เมื่อแอปอยู่ในพื้นหลัง รูปโปรไฟล์ อนุญาตให้ผู้ใช้สามารถอัปโหลดอวาตาร์ การปรับปรุงความปลอดภัย ปกป้องข้อมูลด้วย acls และการอนุญาตตามบทบาท แหล่งข้อมูลเพิ่มเติม เอกสาร back4app https //www back4app com/docs คู่มือ parse sdk สำหรับ flutter https //docs parseplatform org/flutter/guide/ เอกสารทางการ flutter https //flutter dev/docs parse live query https //docs parseplatform org/js/guide/#live queries เขียนโค้ดให้สนุก!