Flutter Templates
สร้างแอปโซเชียลเน็ตเวิร์กด้วย Flutter และ Back4App
54 นาที
บทนำ การสร้างแอปโซเชียลเน็ตเวิร์กอาจเป็นงานที่ซับซ้อน แต่ด้วย flutter และ back4app คุณสามารถทำให้กระบวนการพัฒนาง่ายขึ้น บทแนะนำนี้จะพาคุณไปสร้างแอปโซเชียลเน็ตเวิร์กที่มีฟีเจอร์ครบถ้วน ซึ่งรวมถึงการยืนยันตัวตนของผู้ใช้ การจัดการโปรไฟล์ ฟีดข่าว การเชื่อมต่อเพื่อน การส่งข้อความ และการแจ้งเตือน เมื่อสิ้นสุดบทแนะนำนี้ คุณจะมีแอปโซเชียลเน็ตเวิร์กที่ใช้งานได้พร้อมฟีเจอร์ดังต่อไปนี้ การยืนยันตัวตนของผู้ใช้ กระบวนการลงทะเบียนและเข้าสู่ระบบที่ปลอดภัย โปรไฟล์ผู้ใช้ โปรไฟล์ที่แก้ไขได้พร้อมข้อมูลผู้ใช้ ฟีดข่าว แสดงโพสต์จากเพื่อนและผู้ใช้ การเชื่อมต่อเพื่อน ความสามารถในการส่งและรับคำขอเป็นเพื่อน การส่งข้อความ การแชทแบบเรียลไทม์ระหว่างผู้ใช้ การแจ้งเตือน การแจ้งเตือนแบบพุชสำหรับคำขอเป็นเพื่อน ข้อความ และการโต้ตอบโพสต์ ข้อกำหนดเบื้องต้น ในการติดตามบทแนะนำนี้ คุณจะต้องมี flutter sdk ติดตั้งบนเครื่องของคุณ ทำตาม คู่มือการติดตั้ง flutter อย่างเป็นทางการ https //flutter dev/docs/get started/install สำหรับระบบปฏิบัติการของคุณ ความรู้พื้นฐานเกี่ยวกับ flutter และ dart หากคุณเป็นมือใหม่กับ flutter ให้ตรวจสอบ เอกสาร flutter https //flutter dev/docs เพื่อทำความคุ้นเคยกับพื้นฐาน ide หรือโปรแกรมแก้ไขข้อความ เช่น visual studio code หรือ android studio บัญชี back4app ลงทะเบียนสำหรับบัญชีฟรีที่ back4app https //www back4app com/ parse server sdk สำหรับ flutter เพิ่มในโปรเจกต์ของคุณ เรียนรู้วิธีการตั้งค่าโดยทำตาม คู่มือ back4app flutter sdk https //www back4app com/docs/flutter/parse flutter sdk ขั้นตอนที่ 1 – การตั้งค่าโปรเจกต์ flutter 1 1 สร้างโปรเจกต์ flutter ใหม่ เปิดเทอร์มินัลของคุณและรัน flutter create social app ไปที่ไดเรกทอรีโปรเจกต์ cd social app 1 2 เพิ่ม dependencies เปิด pubspec yaml และเพิ่ม dependencies ต่อไปนี้ dependencies flutter sdk flutter parse server sdk flutter ^4 0 1 provider ^6 0 0 image picker ^0 8 4+6 cached network image ^3 2 0 firebase messaging ^11 2 8 uuid ^3 0 6 รัน flutter pub get เพื่อติดตั้งแพ็คเกจ หมายเหตุ เรากำลังใช้ parse server sdk flutter สำหรับการรวม back4app provider สำหรับการจัดการสถานะ image picker สำหรับการเลือกภาพโปรไฟล์และโพสต์ cached network image สำหรับการโหลดภาพอย่างมีประสิทธิภาพ firebase messaging สำหรับการแจ้งเตือนแบบพุช uuid สำหรับการสร้าง id ที่ไม่ซ้ำกัน ขั้นตอนที่ 2 – การตั้งค่า back4app 2 1 สร้างแอปพลิเคชัน back4app ใหม่ เข้าสู่ระบบที่ แดชบอร์ด back4app https //dashboard back4app com/ คลิกที่ "สร้างแอปใหม่" ใส่ชื่อสำหรับแอปพลิเคชันของคุณ เช่น "socialapp" , และคลิก "สร้าง" 2 2 ตั้งค่าข้อมูลโมเดล เราจะต้องสร้างหลายคลาสใน back4app ผู้ใช้ คลาสที่สร้างขึ้นสำหรับการตรวจสอบสิทธิ์ผู้ใช้ โปรไฟล์ เก็บข้อมูลโปรไฟล์ของผู้ใช้ โพสต์ เก็บโพสต์ของผู้ใช้ คำขอเพื่อน จัดการคำขอเพื่อนระหว่างผู้ใช้ ข้อความ เก็บข้อความระหว่างผู้ใช้ 2 2 1 โปรไฟล์คลาส ไปที่ "ฐานข้อมูล" ส่วน คลิกที่ "สร้างคลาส" ในโมดัล เลือก "กำหนดเอง" ป้อน "โปรไฟล์" เป็นชื่อคลาส คลิก "สร้างคลาส" เพิ่มคอลัมน์ต่อไปนี้ ผู้ใช้ พิมพ์ pointer< user> ชื่อผู้ใช้ พิมพ์ string ชื่อเต็ม พิมพ์ string ชีวประวัติ พิมพ์ string รูปโปรไฟล์ พิมพ์ file 2 2 2 โพสต์คลาส สร้าง "โพสต์" คลาสที่มีคอลัมน์ดังต่อไปนี้ ผู้ใช้ ประเภท pointer< user> เนื้อหา ประเภท string ภาพ ประเภท file สร้างเมื่อ ประเภท date 2 2 3 คลาส friendrequest สร้าง "friendrequest" คลาสที่มีคอลัมน์ดังต่อไปนี้ จากผู้ใช้ ประเภท pointer< user> ถึงผู้ใช้ ประเภท pointer< user> สถานะ ประเภท string (ค่าที่เป็นไปได้ "รอดำเนินการ", "ยอมรับ", "ปฏิเสธ") 2 2 4 คลาสข้อความ สร้าง "ข้อความ" คลาสที่มีคอลัมน์ดังต่อไปนี้ จากผู้ใช้ ประเภท pointer< user> ถึงผู้ใช้ ประเภท pointer< user> เนื้อหา ประเภท string สร้างเมื่อ ประเภท date 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 'package\ provider/provider dart'; import 'services/auth service dart'; import 'screens/login screen dart'; 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 changenotifierprovider\<authservice>( create ( ) => authservice(), child materialapp( title 'social app', theme themedata( primaryswatch colors blue, ), home loginscreen(), ), ); } } แทนที่ 'your application id' และ 'your client key' ด้วยข้อมูลรับรอง back4app ของคุณ เรากำลังใช้ changenotifierprovider เพื่อจัดการสถานะการรับรองตัวตน ขั้นตอนที่ 4 – การดำเนินการรับรองตัวตนของผู้ใช้ 4 1 สร้างบริการการตรวจสอบสิทธิ์ สร้างไดเรกทอรีใหม่ชื่อ services ภายใต้ lib และเพิ่มไฟล์ชื่อ auth service dart // lib/services/auth service dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; class authservice with changenotifier { parseuser? user; future\<bool> signup(string username, string password, string email) async { user = parseuser createuser(username, password, email); final response = await user! signup(); if (response success) { notifylisteners(); return true; } else { user = null; return false; } } future\<bool> login(string username, string password) async { user = parseuser(username, password, null); final response = await user! login(); if (response success) { notifylisteners(); return true; } else { user = null; return false; } } future\<void> logout() async { if (user != null) { await user! logout(); user = null; notifylisteners(); } } bool get isauthenticated => user != null; } 4 2 สร้างหน้าจอเข้าสู่ระบบและลงทะเบียน สร้างไดเรกทอรีชื่อ screens ภายใต้ lib และเพิ่ม login screen dart และ signup screen dart 4 2 1 หน้าจอเข้าสู่ระบบ // lib/screens/login screen dart import 'package\ flutter/material dart'; import 'package\ provider/provider dart'; import ' /services/auth service dart'; import 'signup screen dart'; import 'home screen dart'; class loginscreen extends statefulwidget { @override loginscreenstate createstate() => loginscreenstate(); } class loginscreenstate extends state\<loginscreen> { final texteditingcontroller usernamecontroller = texteditingcontroller(); final texteditingcontroller passwordcontroller = texteditingcontroller(); void login() async { final authservice = provider of\<authservice>(context, listen false); bool success = await authservice login( usernamecontroller text trim(), passwordcontroller text trim(), ); if (success) { 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('social 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, child text('login')), textbutton( onpressed () { navigator push( context, materialpageroute(builder ( ) => signupscreen()), ); }, child text('don\\'t have an account? sign up'), ) ], ), ), ); } } 4 2 2 หน้าจอสมัครสมาชิก // lib/screens/signup screen dart import 'package\ flutter/material dart'; import 'package\ provider/provider dart'; import ' /services/auth service dart'; import 'home screen dart'; class signupscreen extends statefulwidget { @override signupscreenstate createstate() => signupscreenstate(); } class signupscreenstate extends state\<signupscreen> { final texteditingcontroller usernamecontroller = texteditingcontroller(); final texteditingcontroller passwordcontroller = texteditingcontroller(); final texteditingcontroller emailcontroller = texteditingcontroller(); void signup() async { final authservice = provider of\<authservice>(context, listen false); bool success = await authservice signup( usernamecontroller text trim(), passwordcontroller text trim(), emailcontroller text trim(), ); if (success) { navigator pushreplacement( context, materialpageroute(builder (context) => homescreen()), ); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('signup failed'))); } } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('social app signup'), ), 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, child text('sign up')), ], ), ), ); } } ขั้นตอนที่ 5 – การตั้งค่าโปรไฟล์ผู้ใช้ 5 1 สร้างบริการโปรไฟล์ เพิ่มไฟล์ชื่อ profile service dart ใน lib/services/ // lib/services/profile service dart import 'package\ parse server sdk flutter/parse server sdk dart'; import ' /models/profile dart'; class profileservice { future\<void> createprofile(parseuser user) async { final profile = parseobject('profile') set('user', user) set('username', user username); await profile save(); } future\<profile?> getprofile(parseuser user) async { final query = querybuilder\<parseobject>(parseobject('profile')) whereequalto('user', user); final response = await query query(); if (response success && response results != null) { final profileobject = response results! first; return profile fromparseobject(profileobject); } else { return null; } } future\<void> updateprofile(profile profile) async { final profileobject = parseobject('profile') objectid = profile id set('fullname', profile fullname) set('bio', profile bio); await profileobject save(); } } 5 2 สร้างโมเดลโปรไฟล์ เพิ่มไฟล์ชื่อ profile dart ใน lib/models/ // lib/models/profile dart import 'package\ parse server sdk flutter/parse server sdk dart'; class profile { string id; string username; string? fullname; string? bio; parsefilebase? profilepicture; profile({ required this id, required this username, this fullname, this bio, this profilepicture, }); factory profile fromparseobject(parseobject object) { return profile( id object objectid!, username object get\<string>('username')!, fullname object get\<string>('fullname'), bio object get\<string>('bio'), profilepicture object get\<parsefilebase>('profilepicture'), ); } } 5 3 สร้างหน้าจอโปรไฟล์ เพิ่มไฟล์ชื่อ profile screen dart ใน lib/screens/ // lib/screens/profile screen dart import 'package\ flutter/material dart'; import 'package\ provider/provider dart'; import ' /services/auth service dart'; import ' /services/profile service dart'; import ' /models/profile dart'; class profilescreen extends statefulwidget { @override profilescreenstate createstate() => profilescreenstate(); } class profilescreenstate extends state\<profilescreen> { final profileservice profileservice = profileservice(); profile? profile; final texteditingcontroller fullnamecontroller = texteditingcontroller(); final texteditingcontroller biocontroller = texteditingcontroller(); void loadprofile() async { final authservice = provider of\<authservice>(context, listen false); final user = authservice user!; profile? fetchedprofile = await profileservice getprofile(user); if (fetchedprofile == null) { await profileservice createprofile(user); fetchedprofile = await profileservice getprofile(user); } setstate(() { profile = fetchedprofile; fullnamecontroller text = profile? fullname ?? ''; biocontroller text = profile? bio ?? ''; }); } void saveprofile() async { if (profile != null) { profile! fullname = fullnamecontroller text trim(); profile! bio = biocontroller text trim(); await profileservice updateprofile(profile!); scaffoldmessenger of(context) showsnackbar(snackbar(content text('profile updated'))); } } @override void initstate() { super initstate(); loadprofile(); } @override widget build(buildcontext context) { if (profile == null) { return scaffold( appbar appbar(title text('profile')), body center(child circularprogressindicator()), ); } return scaffold( appbar appbar(title text(profile! username)), body padding( padding const edgeinsets all(16), child column( children \[ // add profile picture handling here textfield( controller fullnamecontroller, decoration inputdecoration(labeltext 'full name'), ), textfield( controller biocontroller, decoration inputdecoration(labeltext 'bio'), ), sizedbox(height 20), elevatedbutton(onpressed saveprofile, child text('save')), ], ), ), ); } } ขั้นตอนที่ 6 – การนำเสนอข่าวสาร 6 1 สร้างบริการโพสต์ เพิ่มไฟล์ชื่อ post service dart ใน lib/services/ // lib/services/post service dart import 'package\ parse server sdk flutter/parse server sdk dart'; import ' /models/post dart'; class postservice { future\<void> createpost(string content, parseuser user) async { final post = parseobject('post') set('user', user) set('content', content); await post save(); } future\<list\<post>> getposts(parseuser user) async { final query = querybuilder\<parseobject>(parseobject('post')) orderbydescending('createdat') includeobject(\['user']); final response = await query query(); if (response success && response results != null) { return response results! map((e) => post fromparseobject(e)) tolist(); } else { return \[]; } } } 6 2 สร้างโมเดลโพสต์ เพิ่มไฟล์ชื่อ post dart ใน lib/models/ // lib/models/post dart import 'package\ parse server sdk flutter/parse server sdk dart'; class post { string id; string content; parseuser user; datetime createdat; post({ required this id, required this content, required this user, required this createdat, }); factory post fromparseobject(parseobject object) { return post( id object objectid!, content object get\<string>('content')!, user object get\<parseuser>('user')!, createdat object createdat!, ); } } 6 3 สร้างหน้าหลัก แก้ไข home screen dart ใน lib/screens/ // lib/screens/home screen dart import 'package\ flutter/material dart'; import 'package\ provider/provider dart'; import ' /services/auth service dart'; import ' /services/post service dart'; import ' /models/post dart'; import 'profile screen dart'; class homescreen extends statefulwidget { @override homescreenstate createstate() => homescreenstate(); } class homescreenstate extends state\<homescreen> { final postservice postservice = postservice(); list\<post> posts = \[]; final texteditingcontroller postcontroller = texteditingcontroller(); void loadposts() async { final authservice = provider of\<authservice>(context, listen false); final user = authservice user!; list\<post> fetchedposts = await postservice getposts(user); setstate(() { posts = fetchedposts; }); } void createpost() async { final authservice = provider of\<authservice>(context, listen false); final user = authservice user!; await postservice createpost( postcontroller text trim(), user); postcontroller clear(); loadposts(); } @override void initstate() { super initstate(); loadposts(); } @override widget build(buildcontext context) { final authservice = provider of\<authservice>(context); return scaffold( appbar appbar( title text('social app'), actions \[ iconbutton( icon icon(icons person), onpressed () { navigator push( context, materialpageroute(builder ( ) => profilescreen()), ); }, ), iconbutton( icon icon(icons logout), onpressed () async { await authservice logout(); navigator pushreplacementnamed(context, '/'); }, ), ], ), body column( children \[ textfield( controller postcontroller, decoration inputdecoration( hinttext 'what\\'s on your mind?', contentpadding edgeinsets all(16), ), ), elevatedbutton(onpressed createpost, child text('post')), expanded( child listview\ builder( itemcount posts length, itembuilder (context, index) { final post = posts\[index]; return listtile( title text(post user username ?? 'unknown'), subtitle text(post content), trailing text( post createdat tolocal() tostring(), style textstyle(fontsize 12), ), ); }, ), ), ], ), ); } } ขั้นตอนที่ 7 – การเพิ่มการเชื่อมต่อเพื่อน ในขั้นตอนนี้ เราจะดำเนินการเชื่อมต่อเพื่อนระหว่างผู้ใช้ ผู้ใช้สามารถส่งคำขอเป็นเพื่อน ยอมรับหรือปฏิเสธคำขอเหล่านั้น และดูรายชื่อเพื่อนของตน เราจะปรับเปลี่ยนโมเดลข้อมูล สร้างบริการ และอัปเดต ui เพื่อรองรับฟังก์ชันนี้ 7 1 อัปเดตโมเดลข้อมูล เราได้สร้างคลาส friendrequest ใน back4app พร้อมกับคอลัมน์ต่อไปนี้ fromuser ชี้ไปที่ user touser ชี้ไปที่ user status สตริง (ค่า "pending", "accepted", "rejected") นอกจากนี้เราจำเป็นต้องติดตามรายชื่อเพื่อนของผู้ใช้ เราสามารถทำได้โดยการเพิ่ม friends ความสัมพันธ์ใน user คลาส 7 1 1 เพิ่มความสัมพันธ์เพื่อนในคลาสผู้ใช้ ใน back4app ให้ไปที่ user คลาส คลิกที่ "+" ปุ่มเพื่อเพิ่มคอลัมน์ใหม่ ตั้งชื่อคอลัมน์ว่า "friends" และตั้งประเภทเป็น relation < user> 7 2 สร้างบริการคำขอเพื่อน สร้างไฟล์ชื่อ friend service dart ใน lib/services/ // lib/services/friend service dart import 'package\ parse server sdk flutter/parse server sdk dart'; class friendservice { future\<bool> sendfriendrequest(parseuser fromuser, parseuser touser) async { final friendrequest = parseobject('friendrequest') set('fromuser', fromuser) set('touser', touser) set('status', 'pending'); final response = await friendrequest save(); return response success; } future\<list\<parseobject>> getpendingrequests(parseuser user) async { final query = querybuilder\<parseobject>(parseobject('friendrequest')) whereequalto('touser', user) whereequalto('status', 'pending') includeobject(\['fromuser']); final response = await query query(); if (response success && response results != null) { return response results!; } else { return \[]; } } future\<bool> acceptfriendrequest(parseobject friendrequest) async { friendrequest set('status', 'accepted'); final response = await friendrequest save(); if (response success) { // add each user to the other's friends relation final fromuser = friendrequest get\<parseuser>('fromuser')!; final touser = friendrequest get\<parseuser>('touser')!; fromuser setadd('friends', \[touser]); touser setadd('friends', \[fromuser]); await fromuser save(); await touser save(); return true; } return false; } future\<bool> rejectfriendrequest(parseobject friendrequest) async { friendrequest set('status', 'rejected'); final response = await friendrequest save(); return response success; } future\<list\<parseuser>> getfriends(parseuser user) async { final relation = user getrelation\<parseuser>('friends'); final query = relation query(); final response = await query query(); if (response success && response results != null) { return response results! cast\<parseuser>(); } else { return \[]; } } } 7 3 อัปเดต ui 7 3 1 เพิ่มหน้าค้นหาผู้ใช้ สร้างไฟล์ชื่อ search users screen dart ใน lib/screens/ // lib/screens/search users screen dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'package\ provider/provider dart'; import ' /services/auth service dart'; import ' /services/friend service dart'; class searchusersscreen extends statefulwidget { @override searchusersscreenstate createstate() => searchusersscreenstate(); } class searchusersscreenstate extends state\<searchusersscreen> { final texteditingcontroller searchcontroller = texteditingcontroller(); list\<parseuser> users = \[]; final friendservice friendservice = friendservice(); void searchusers() async { final query = querybuilder\<parseuser>(parseuser forquery()) wherecontains('username', searchcontroller text trim()) wherenotequalto('objectid', provider of\<authservice>(context, listen false) user! objectid); final response = await query query(); if (response success && response results != null) { setstate(() { users = response results! cast\<parseuser>(); }); } else { setstate(() { users = \[]; }); } } void sendfriendrequest(parseuser touser) async { final fromuser = provider of\<authservice>(context, listen false) user!; bool success = await friendservice sendfriendrequest(fromuser, touser); if (success) { scaffoldmessenger of(context) showsnackbar(snackbar(content text('friend request sent'))); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('failed to send friend request'))); } } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('search users'), ), body column( children \[ padding( padding const edgeinsets all(16 0), child textfield( controller searchcontroller, decoration inputdecoration( hinttext 'search by username', suffixicon iconbutton( icon icon(icons search), onpressed searchusers, ), ), ), ), expanded( child listview\ builder( itemcount users length, itembuilder (context, index) { final user = users\[index]; return listtile( title text(user username ?? 'unknown'), trailing elevatedbutton( onpressed () => sendfriendrequest(user), child text('add friend'), ), ); }, ), ), ], ), ); } } 7 3 2 หน้าคำขอเพื่อน สร้างไฟล์ชื่อ friend requests screen dart ใน lib/screens/ // lib/screens/friend requests screen dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'package\ provider/provider dart'; import ' /services/auth service dart'; import ' /services/friend service dart'; class friendrequestsscreen extends statefulwidget { @override friendrequestsscreenstate createstate() => friendrequestsscreenstate(); } class friendrequestsscreenstate extends state\<friendrequestsscreen> { final friendservice friendservice = friendservice(); list\<parseobject> friendrequests = \[]; void loadfriendrequests() async { final user = provider of\<authservice>(context, listen false) user!; final requests = await friendservice getpendingrequests(user); setstate(() { friendrequests = requests; }); } void acceptrequest(parseobject request) async { bool success = await friendservice acceptfriendrequest(request); if (success) { scaffoldmessenger of(context) showsnackbar(snackbar(content text('friend request accepted'))); loadfriendrequests(); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('failed to accept friend request'))); } } void rejectrequest(parseobject request) async { bool success = await friendservice rejectfriendrequest(request); if (success) { scaffoldmessenger of(context) showsnackbar(snackbar(content text('friend request rejected'))); loadfriendrequests(); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('failed to reject friend request'))); } } @override void initstate() { super initstate(); loadfriendrequests(); } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('friend requests'), ), body listview\ builder( itemcount friendrequests length, itembuilder (context, index) { final request = friendrequests\[index]; final fromuser = request get\<parseuser>('fromuser')!; return listtile( title text(fromuser username ?? 'unknown'), subtitle text('sent you a friend request'), trailing row( mainaxissize mainaxissize min, children \[ iconbutton( icon icon(icons check, color colors green), onpressed () => acceptrequest(request), ), iconbutton( icon icon(icons close, color colors red), onpressed () => rejectrequest(request), ), ], ), ); }, ), ); } } 7 3 3 อัปเดตการนำทางหน้าหลัก ใน home screen dart , เพิ่มการนำทางไปยังหน้าค้นหาผู้ใช้และหน้าคำขอเพื่อน // inside appbar actions iconbutton( icon icon(icons person add), onpressed () { navigator push( context, materialpageroute(builder ( ) => searchusersscreen()), ); }, ), iconbutton( icon icon(icons notifications), onpressed () { navigator push( context, materialpageroute(builder ( ) => friendrequestsscreen()), ); }, ), 7 4 อัปเดตฟีดข่าวเพื่อแสดงโพสต์ของเพื่อน ปรับเปลี่ยน getposts เมธอดใน post service dart เพื่อดึงโพสต์จากผู้ใช้และเพื่อนของพวกเขา // lib/services/post service dart future\<list\<post>> getposts(parseuser user) async { // get friends final relation = user getrelation\<parseuser>('friends'); final friendsquery = relation query(); final friendsresponse = await friendsquery query(); list\<string> userids = \[user objectid!]; if (friendsresponse success && friendsresponse results != null) { final friends = friendsresponse results! cast\<parseuser>(); userids addall(friends map((friend) => friend objectid!)); } // fetch posts from user and friends final query = querybuilder\<parseobject>(parseobject('post')) wherecontainedin('user', userids map((id) => parseuser(null, null, null) objectid = id) tolist()) orderbydescending('createdat') includeobject(\['user']); final response = await query query(); if (response success && response results != null) { return response results! map((e) => post fromparseobject(e)) tolist(); } else { return \[]; } } ขั้นตอนที่ 8 – การนำเสนอการส่งข้อความ ในขั้นตอนนี้ เราจะเพิ่มการส่งข้อความแบบเรียลไทม์ระหว่างผู้ใช้โดยใช้ live queries 8 1 เปิดใช้งาน live queries ใน back4app ในแดชบอร์ดแอป back4app ของคุณ ให้ไปที่ app settings > server settings ภายใต้ server url , จดบันทึก url เซิร์ฟเวอร์ของคุณ (เช่น https //your app name back4app io ) live queries เปิดใช้งานโดยค่าเริ่มต้นใน back4app 8 2 ตั้งค่า live queries ใน flutter แพ็คเกจ parse server sdk flutter รวมการสนับสนุน live query 8 3 สร้างบริการส่งข้อความ สร้างไฟล์ชื่อ message service dart ใน lib/services/ // lib/services/message service dart import 'package\ parse server sdk flutter/parse server sdk dart'; import ' /models/message dart'; class messageservice { parselivelist\<message>? livemessagelist; future\<void> sendmessage(parseuser fromuser, parseuser touser, string content) async { final message = parseobject('message') set('fromuser', fromuser) set('touser', touser) set('content', content); await message save(); } future\<void> subscribetomessages(parseuser user, parseuser otheruser, function(list\<message>) onmessagesupdated) async { final querybuilder = querybuilder\<parseobject>(parseobject('message')) whereequalto('fromuser', user) whereequalto('touser', otheruser) orderbyascending('createdat') includeobject(\['fromuser', 'touser']); livemessagelist = parselivelist\<message>(querybuilder, listenonallsubitems true); livemessagelist! stream listen((event) { onmessagesupdated(livemessagelist! items); }); } future\<void> dispose() async { await livemessagelist? dispose(); } } 8 4 สร้างโมเดลข้อความ เพิ่มไฟล์ชื่อ message dart ใน lib/models/ // lib/models/message dart import 'package\ parse server sdk flutter/parse server sdk dart'; class message extends parseobject implements parsecloneable { message() super('message'); message clone() this(); @override clone(map\<string, dynamic> map) => message clone() fromjson(map); parseuser get fromuser => get\<parseuser>('fromuser')!; parseuser get touser => get\<parseuser>('touser')!; string get content => get\<string>('content')!; } 8 5 สร้างหน้าจอแชท เพิ่มไฟล์ชื่อ chat screen dart ภายใต้ lib/screens/ // lib/screens/chat screen dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'package\ provider/provider dart'; import ' /models/message dart'; import ' /services/auth service dart'; import ' /services/message service dart'; class chatscreen extends statefulwidget { final parseuser otheruser; chatscreen({required this otheruser}); @override chatscreenstate createstate() => chatscreenstate(); } class chatscreenstate extends state\<chatscreen> { final messageservice messageservice = messageservice(); list\<message> messages = \[]; final texteditingcontroller messagecontroller = texteditingcontroller(); void sendmessage() { final authservice = provider of\<authservice>(context, listen false); final fromuser = authservice user!; final touser = widget otheruser; messageservice sendmessage(fromuser, touser, messagecontroller text trim()); messagecontroller clear(); } void onmessagesupdated(list\<message> updatedmessages) { setstate(() { messages = updatedmessages; }); } @override void initstate() { super initstate(); final authservice = provider of\<authservice>(context, listen false); final user = authservice user!; messageservice subscribetomessages(user, widget otheruser, onmessagesupdated); } @override void dispose() { messageservice dispose(); super dispose(); } @override widget build(buildcontext context) { final authservice = provider of\<authservice>(context, listen false); final user = authservice user!; return scaffold( appbar appbar(title text(widget otheruser username ?? 'chat')), body column( children \[ expanded( child listview( children messages map((message) { bool isme = message fromuser objectid == user objectid; return listtile( title align( alignment isme ? alignment centerright alignment centerleft, child container( padding edgeinsets all(10), color isme ? colors blueaccent colors grey\[300], child text( message content, style textstyle(color isme ? colors white colors black), ), ), ), ); }) tolist(), ), ), divider(height 1), container( padding edgeinsets symmetric(horizontal 8 0), color theme of(context) cardcolor, child row( children \[ flexible( child textfield( controller messagecontroller, decoration inputdecoration collapsed(hinttext 'send a message'), ), ), iconbutton( icon icon(icons send), onpressed sendmessage, ), ], ), ) ], ), ); } } 8 6 อัปเดต ui เพื่อเริ่มแชท คุณสามารถเริ่มการสนทนาจากรายชื่อเพื่อนหรือหน้าค้นหาผู้ใช้ ในรายชื่อเพื่อน เมื่อแสดงเพื่อน ให้เพิ่มปุ่มเพื่อเริ่มการสนทนา // inside the listtile for a friend trailing iconbutton( icon icon(icons chat), onpressed () { navigator push( context, materialpageroute(builder ( ) => chatscreen(otheruser friend)), ); }, ), ขั้นตอนที่ 9 – การเพิ่มการแจ้งเตือนแบบพุช การใช้งานการแจ้งเตือนแบบพุชเกี่ยวข้องกับการตั้งค่า firebase cloud messaging (fcm) และการรวมเข้ากับ back4app 9 1 ตั้งค่า firebase cloud messaging 9 1 1 ตั้งค่าโปรเจกต์ firebase ไปที่ firebase console https //console firebase google com/ และสร้างโปรเจกต์ใหม่ เพิ่มแอป android และ/หรือ ios ลงในโปรเจกต์ของคุณ สำหรับ android คุณต้องใช้ชื่อแพ็กเกจ (applicationid) สำหรับ ios คุณต้องใช้ bundle identifier 9 1 2 ดาวน์โหลดไฟล์การตั้งค่า สำหรับ android ดาวน์โหลด google services json และวางไว้ใน android/app/ สำหรับ ios ดาวน์โหลด googleservice info plist และเพิ่มลงในโปรเจกต์ xcode ของคุณภายใต้ runner 9 2 เพิ่ม firebase messaging แพ็กเกจ ตรวจสอบให้แน่ใจว่าคุณได้เพิ่ม firebase messaging ลงใน pubspec yaml dependencies firebase messaging ^11 2 8 รัน flutter pub get เพื่อทำการติดตั้ง 9 3 เริ่มต้น firebase ใน flutter แก้ไข main dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'package\ firebase core/firebase core dart'; // other imports void main() async { widgetsflutterbinding ensureinitialized(); await firebase initializeapp(); // initialize parse as before runapp(myapp()); } 9 4 ตั้งค่า firebase messaging สร้างไฟล์ชื่อ push notification service dart ใน lib/services/ // lib/services/push notification service dart import 'package\ firebase messaging/firebase messaging dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; class pushnotificationservice { final firebasemessaging fcm = firebasemessaging instance; future\<void> init() async { // request permissions (ios) await fcm requestpermission(); // get the token string? token = await fcm gettoken(); if (token != null) { // save the token to parse installation final installation = await parseinstallation currentinstallation(); installation set('devicetoken', token); await installation save(); } // handle foreground messages firebasemessaging onmessage listen((remotemessage message) { print('received a message in the foreground!'); // handle the message }); } } 9 5 อัปเดต main dart เพื่อเริ่มต้น push notifications ใน main dart , หลังจากเริ่มต้น parse ให้เริ่มต้น pushnotificationservice void main() async { widgetsflutterbinding ensureinitialized(); await firebase initializeapp(); // initialize parse as before // initialize push notifications pushnotificationservice pushnotificationservice = pushnotificationservice(); await pushnotificationservice init(); runapp(myapp()); } 9 6 การส่ง push notifications จาก back4app คุณสามารถส่งการแจ้งเตือนแบบพุชโดยใช้ cloud code หรือโดยตรงจากเซิร์ฟเวอร์ของคุณ 9 6 1 การส่งการแจ้งเตือนเมื่อมีการขอเป็นเพื่อน เมื่อผู้ใช้ส่งคำขอเป็นเพื่อน คุณสามารถส่งการแจ้งเตือนแบบพุชไปยังผู้รับ ใน friend service dart , แก้ไข sendfriendrequest เมธอด future\<bool> sendfriendrequest(parseuser fromuser, parseuser touser) async { // existing code to create friend request // send push notification final pushquery = querybuilder\<parseinstallation>(parseinstallation forquery()) whereequalto('user', touser); await parsepush() send( pushpayload( query pushquery, notification parsenotification( title 'new friend request', alert '${fromuser username} sent you a friend request', ), ), ); return response success; } หมายเหตุ ตรวจสอบให้แน่ใจว่าคุณได้เชื่อมโยงการติดตั้งกับผู้ใช้ 9 7 เชื่อมโยงการติดตั้งกับผู้ใช้ เมื่อผู้ใช้เข้าสู่ระบบ ให้เชื่อมโยงการติดตั้งของพวกเขากับบัญชีผู้ใช้ ใน auth service dart , หลังจากเข้าสู่ระบบสำเร็จ future\<bool> login(string username, string password) async { user = parseuser(username, password, null); final response = await user! login(); if (response success) { // associate installation with user final installation = await parseinstallation currentinstallation(); installation set('user', user); await installation save(); notifylisteners(); return true; } else { user = null; return false; } } future\<bool> sendfriendrequest(parseuser fromuser, parseuser touser) async { // existing code to create friend request // send push notification final pushquery = querybuilder\<parseinstallation>(parseinstallation forquery()) whereequalto('user', touser); await parsepush() send( pushpayload( query pushquery, notification parsenotification( title 'new friend request', alert '${fromuser username} sent you a friend request', ), ), ); return response success; } future\<bool> login(string username, string password) async { user = parseuser(username, password, null); final response = await user! login(); if (response success) { // associate installation with user final installation = await parseinstallation currentinstallation(); installation set('user', user); await installation save(); notifylisteners(); return true; } else { user = null; return false; } } หมายเหตุ ตรวจสอบให้แน่ใจว่าคุณได้เชื่อมโยงการติดตั้งกับผู้ใช้ หมายเหตุ การแจ้งเตือนแบบพุชต้องการการตั้งค่าเพิ่มเติมทั้งในฝั่งลูกค้าและเซิร์ฟเวอร์ คุณต้องจัดการกับสถานการณ์ที่แตกต่างกัน เช่น การแจ้งเตือนในพื้นหลังและสิทธิ์ของผู้ใช้ ซึ่งอยู่นอกเหนือขอบเขตของบทเรียนนี้ บทสรุป ขอแสดงความยินดี! คุณได้สร้างพื้นฐานของแอปโซเชียลเน็ตเวิร์กโดยใช้ flutter และ back4app แอปนี้รวมถึงการตรวจสอบสิทธิ์ผู้ใช้ การจัดการโปรไฟล์ และฟีเจอร์ฟีดข่าว ในขณะที่การดำเนินการเชื่อมต่อเพื่อน การส่งข้อความ และการแจ้งเตือนนั้นอยู่นอกเหนือขอบเขตของบทเรียนนี้ แต่ตอนนี้คุณมีโครงสร้างที่จำเป็นในการขยายแอปของคุณต่อไป ขั้นตอนถัดไป การเชื่อมต่อเพื่อน นำฟังก์ชันการขอเป็นเพื่อนมาใช้ การส่งข้อความ เพิ่มฟีเจอร์แชทแบบเรียลไทม์โดยใช้ live queries การแจ้งเตือน รวมการแจ้งเตือนแบบพุชเพื่อการมีส่วนร่วมของผู้ใช้ การปรับปรุง ui ปรับปรุงส่วนติดต่อผู้ใช้และประสบการณ์ผู้ใช้ ความปลอดภัย รับรองความปลอดภัยและความเป็นส่วนตัวของข้อมูลโดยการตั้งค่า acl ที่เหมาะสมใน back4app แหล่งข้อมูลเพิ่มเติม เอกสาร back4app https //www back4app com/docs คู่มือ parse sdk สำหรับ flutter https //docs parseplatform org/flutter/guide/ เอกสารอย่างเป็นทางการของ flutter https //flutter dev/docs เอกสารแพ็คเกจ provider https //pub dev/packages/provider เขียนโค้ดให้สนุก!