Flutter Templates
FlutterとBack4Appを使用したソーシャルネットワーキングアプリの構築
52 分
はじめに ソーシャルネットワーキングアプリを作成することは複雑な作業ですが、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/ に無料アカウントを登録してください。 flutter用のparse server sdk があなたのプロジェクトに追加されていること。 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 プロファイルクラス 「 "database" 」セクションに移動します。 「 "create a class" 」をクリックします。 モーダルで 「 "custom" 」を選択します。 クラス名として「 "profile" 」を入力します。 「 "create class" 」をクリックします。 次の列を追加します ユーザー タイプ pointer< user> ユーザー名 タイプ string フルネーム タイプ string バイオ タイプ string プロフィール写真 タイプ file 2 2 2 投稿クラス 次の列を持つ "post" クラスを作成します user 型 pointer< user> content 型 string image 型 file createdat 型 date 2 2 3 friendrequest クラス 次の列を持つ "friendrequest" クラスを作成します fromuser 型 pointer< user> touser 型 pointer< user> status 型 string (値 "pending", "accepted", "rejected") 2 2 4 message クラス 次の列を持つ "message" クラスを作成します fromuser 型 pointer< user> touser 型 pointer< user> content 型 string createdat 型 date 2 3 アプリケーションの資格情報を取得する 次に進みます app settings > security & keys あなたの application id と client key をメモしてください ステップ 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(), ), ); } } 「 '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 back4appでlive queriesを有効にする back4appアプリのダッシュボードで、 アプリ設定 > サーバー設定 に移動します。 「 サーバーurl 」の下に、サーバーurl(例: https //your app name back4app io )をメモします。 back4appでは、live queriesがデフォルトで有効になっています。 8 2 flutterでlive queriesを設定する 「 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 コンソール https //console firebase google com/ に移動し、新しいプロジェクトを作成します。 android および/または ios アプリをプロジェクトに追加します。 android の場合、パッケージ名 (applicationid) が必要です。 ios の場合、バンドル識別子が必要です。 9 1 2 設定ファイルのダウンロード android の場合 google services json をダウンロードし、 android/app/ に配置します。 ios の場合 googleservice info plist をダウンロードし、 runner の下に xcode プロジェクトに追加します。 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 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 を更新してプッシュ通知を初期化する で 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; } } 注意 プッシュ通知は、クライアントとサーバーの両方で追加の設定が必要です。バックグラウンド通知やユーザーの権限など、さまざまなシナリオを処理する必要がありますが、これらはこのチュートリアルの範囲を超えています。 結論 おめでとうございます!flutterとback4appを使用して、ソーシャルネットワーキングアプリの基盤を構築しました。このアプリには、ユーザー認証、プロフィール管理、ニュースフィード機能が含まれています。友達の接続、メッセージング、通知の完全な実装はこのチュートリアルの範囲を超えていますが、アプリを拡張するための必要な構造は整っています。 次のステップ 友達の接続 友達リクエスト機能を実装します。 メッセージング live queriesを使用してリアルタイムチャット機能を追加します。 通知 ユーザーエンゲージメントのためにプッシュ通知を統合します。 uiの改善 ユーザーインターフェースとユーザーエクスペリエンスを向上させます。 セキュリティ back4appで適切なaclを設定してデータのセキュリティとプライバシーを確保します。 追加リソース back4appドキュメント https //www back4app com/docs flutter用parse sdkガイド https //docs parseplatform org/flutter/guide/ flutter公式ドキュメント https //flutter dev/docs providerパッケージドキュメント https //pub dev/packages/provider コーディングを楽しんでください!