Flutter Templates
使用Flutter和Back4App构建社交网络应用程序
55 分
介绍 创建社交网络应用程序可能是一项复杂的任务,但使用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 for 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 添加依赖 打开 pubspec yaml 并添加以下依赖 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 帖子类 创建一个 "post" 类,包含以下列: 用户 类型 pointer< user> 内容 类型 string 图片 类型 file 创建时间 类型 date 2 2 3 friendrequest 类 创建一个 "friendrequest" 类,包含以下列: 发件人 类型 pointer< user> 收件人 类型 pointer< user> 状态 类型 string (值 "pending", "accepted", "rejected") 2 2 4 message 类 创建一个 "message" 类,包含以下列: 发件人 类型 pointer< user> 收件人 类型 pointer< user> 内容 类型 string 创建时间 类型 date 2 3 获取应用凭证 导航到 应用设置 > 安全与密钥 。 记下你的 应用 id 和 客户端密钥 。 步骤 3 – 在您的 flutter 应用中初始化 parse 打开 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(), ), ); } } 用您的 back4app 凭据替换 'your application id' 和 'your client key' 我们使用 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步 添加好友连接 在这一步中,我们将实现用户之间的好友连接。用户可以发送好友请求,接受或拒绝请求,并查看他们的好友列表。我们将修改数据模型,创建服务,并更新用户界面以支持此功能。 7 1 更新数据模型 我们已经在 back4app 中创建了 friendrequest 类,包含以下列: fromuser 指向 user touser 指向 user status 字符串(值:"pending", "accepted", "rejected") 此外,我们需要跟踪用户的好友列表。我们可以通过在 friends 关系中添加一个 user 类来实现。 7 1 1 将好友关系添加到用户类 在 back4app 中,转到 user 类。 点击 "+" 按钮以添加新列。 将列命名为 "friends" 并将类型设置为 relation < user> 。 7 2 创建好友请求服务 在 lib/services/ 下创建一个名为 friend service dart 的文件。 // 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 更新用户界面 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 步 – 实现消息功能 在这一步中,我们将使用实时查询在用户之间添加实时消息传递。 8 1 在 back4app 中启用实时查询 在你的 back4app 应用仪表板中,转到 应用设置 > 服务器设置 在 服务器 url , 记下你的服务器 url(例如, https //your app name back4app io )。 实时查询在 back4app 上默认启用。 8 2 在 flutter 中设置实时查询 这个 parse server sdk flutter 包含实时查询支持。 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 更新用户界面以启动聊天 您可以从好友列表或搜索用户屏幕启动聊天。 在好友列表中,显示好友时,添加一个按钮以开始聊天: // inside the listtile for a friend trailing iconbutton( icon icon(icons chat), onpressed () { navigator push( context, materialpageroute(builder ( ) => chatscreen(otheruser friend)), ); }, ), 第 9 步 – 添加推送通知 实现推送通知涉及设置firebase云消息传递(fcm)并将其与back4app集成。 9 1 配置firebase云消息传递 9 1 1 设置firebase项目 前往 firebase控制台 https //console firebase google com/ 并创建一个新项目。 向您的项目添加android和/或ios应用。 对于android,您需要包名(applicationid)。 对于ios,您需要bundle标识符。 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 在 flutter 中初始化 firebase 修改 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 消息推送 创建一个名为 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 以初始化推送通知 在 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 从 back4app 发送推送通知 您可以使用云代码或直接从服务器发送推送通知。 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; } } 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; } } 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 构建了社交网络应用的基础。该应用包括用户身份验证、个人资料管理和新闻推送功能。虽然实现完整的好友连接、消息传递和通知超出了本教程的范围,但您现在拥有继续扩展应用所需的结构。 下一步 好友连接 实现好友请求功能。 消息传递 使用实时查询添加聊天功能。 通知 集成推送通知以提高用户参与度。 用户界面增强 改善用户界面和用户体验。 安全性 通过在 back4app 中设置适当的 acl 确保数据安全和隐私。 附加资源 back4app 文档 https //www back4app com/docs parse sdk for flutter 指南 https //docs parseplatform org/flutter/guide/ flutter 官方文档 https //flutter dev/docs provider 包文档 https //pub dev/packages/provider 快乐编码!