Flutter Templates
플러터와 Back4App을 사용하여 실시간 채팅 애플리케이션 구축하기
35 분
소개 채팅 애플리케이션을 만들려면 실시간 데이터 관리, 사용자 인증, 미디어 처리 및 효율적인 데이터 저장이 필요합니다 이 튜토리얼에서는 1 1 및 그룹 대화, 메시지 상태 및 미디어 공유를 지원하는 flutter에서 실시간 채팅 애플리케이션을 구축하는 방법을 배웁니다 우리는 parse server로 구동되는 백엔드 서비스인 back4app을 사용하여 백엔드 기능을 처리할 것입니다 이 튜토리얼이 끝나면 다음과 같은 기능을 갖춘 완전한 채팅 앱을 갖게 됩니다 사용자 인증 안전한 가입 및 로그인 프로세스 실시간 메시징 라이브 쿼리를 사용한 즉각적인 메시지 전달 사용자 존재 사용자 온라인/오프라인 상태 추적 미디어 저장 채팅에서 이미지 전송 및 수신 메시지 기록 사용자에 대한 채팅 기록 유지 전제 조건 이 튜토리얼을 따라 하려면 다음이 필요합니다 flutter sdk 설치되어 있어야 합니다 공식 flutter 설치 가이드 https //flutter dev/docs/get started/install flutter 및 dart에 대한 기본 지식 ide 또는 텍스트 편집기 (예 visual studio code 또는 android studio) back4app 계정 back4app https //www back4app com/ 에서 무료 계정에 가입하세요 flutter용 parse server sdk 가 프로젝트에 추가되어야 합니다 개요 다음 구성 요소로 채팅 애플리케이션을 구축할 것입니다 사용자 인증 사용자가 가입하고 로그인할 수 있습니다 연락처 목록 채팅할 사용자 목록을 표시합니다 채팅 화면 실시간 메시징 인터페이스 미디어 공유 이미지 전송 및 수신 기능 온라인 상태 사용자의 온라인/오프라인 상태를 표시합니다 1단계 – flutter 프로젝트 설정 1 1 새 flutter 프로젝트 만들기 터미널을 열고 다음을 실행하세요 flutter create chat app 프로젝트 디렉토리로 이동하세요 cd chat app 1 2 의존성 추가 pubspec yaml 파일을 열고 다음 의존성을 추가하세요 dependencies flutter sdk flutter parse server sdk flutter ^4 0 1 image picker ^0 8 4+3 cached network image ^3 2 0 uuid ^3 0 4 flutter pub get 명령어를 실행하여 패키지를 설치하세요 parse server sdk flutter back4app과 상호작용합니다 image picker 갤러리나 카메라에서 이미지를 선택합니다 cached network image 효율적인 이미지 로딩 및 캐싱 uuid 고유 식별자를 생성합니다 2단계 – back4app 설정 2 1 새로운 back4app 애플리케이션 만들기 당신의 back4app 대시보드 https //dashboard back4app com/ 에 로그인하세요 "새 앱 만들기"를 클릭하세요 애플리케이션의 이름을 입력하세요, 예 "chatapp" , 그리고 "생성" 을 클릭하세요 2 2 클래스 및 데이터 모델 구성 다음 클래스를 생성할 것입니다 사용자 (기본 parse 클래스) 사용자 정보를 저장합니다 메시지 채팅 메시지를 저장합니다 채팅방 사용자 간의 채팅을 나타냅니다 2 2 1 사용자 클래스 필드 사용자 이름 문자열 비밀번호 문자열 이메일 문자열 온라인 여부 불리언 아바타 파일 (선택 사항) 이 사용자 클래스는 내장되어 있으며, 추가 필드가 있는지 확인해야 합니다 2 2 2 메시지 클래스 필드 발신자 포인터< 사용자> 수신자 포인터< 사용자> 채팅방 id 문자열 내용 문자열 이미지 파일 (선택 사항) 생성일 날짜 시간 (자동 추가) 2 2 3 채팅방 클래스 필드 chatroomid 문자열 users pointer< user>의 배열 lastmessage 문자열 updatedat datetime (자동 업데이트됨) 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 'screens/login screen dart'; // you'll create this file next void main() async { widgetsflutterbinding ensureinitialized(); const keyapplicationid = 'your application id'; const keyclientkey = 'your client key'; const keyparseserverurl = 'https //parseapi back4app com'; await parse() initialize( keyapplicationid, keyparseserverurl, clientkey keyclientkey, autosendsessionid true, debug true, ); runapp(myapp()); } class myapp extends statelesswidget { @override widget build(buildcontext context) { return materialapp( title 'chat app', theme themedata( primaryswatch colors blue, ), home loginscreen(), ); } } 'your application id'를 'your application id' 및 'your client key' 를 실제 back4app 자격 증명으로 교체하십시오 4단계 – 사용자 인증 구현 4 1 인증 서비스 생성 lib 아래에 services 라는 새 디렉토리를 만들고 auth service dart 라는 파일을 추가하십시오 4 2 로그인 및 회원가입 화면 만들기 새로운 디렉토리를 생성합니다 screens 아래에 lib 그리고 login screen dart 및 signup screen dart 라는 이름의 파일을 추가합니다 4 2 1 로그인 화면 // lib/screens/login screen dart import 'package\ flutter/material dart'; import ' /services/auth service dart'; import 'home screen dart'; import 'signup screen dart'; class loginscreen extends statelesswidget { final authservice authservice = authservice(); final texteditingcontroller usernamecontroller = texteditingcontroller(); final texteditingcontroller passwordcontroller = texteditingcontroller(); void login(buildcontext context) async { var user = await authservice login( usernamecontroller text trim(), passwordcontroller text trim(), ); if (user != null) { navigator pushreplacement( context, materialpageroute(builder (context) => homescreen()), ); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('login failed'))); } } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('chat app login'), ), body padding( padding const edgeinsets all(16), child column( children \[ textfield( controller usernamecontroller, decoration inputdecoration(labeltext 'username'), ), textfield( controller passwordcontroller, decoration inputdecoration(labeltext 'password'), obscuretext true, ), sizedbox(height 20), elevatedbutton( onpressed () => login(context), child text('login'), ), textbutton( onpressed () => navigator push( context, materialpageroute(builder (context) => signupscreen())), child text('don\\'t have an account? sign up'), ), ], ), ), ); } } 4 2 2 가입 화면 // lib/screens/signup screen dart import 'package\ flutter/material dart'; import ' /services/auth service dart'; import 'home screen dart'; class signupscreen extends statelesswidget { final authservice authservice = authservice(); final texteditingcontroller usernamecontroller = texteditingcontroller(); final texteditingcontroller emailcontroller = texteditingcontroller(); final texteditingcontroller passwordcontroller = texteditingcontroller(); void signup(buildcontext context) async { var user = await authservice signup( usernamecontroller text trim(), emailcontroller text trim(), passwordcontroller text trim(), ); if (user != null) { navigator pushreplacement( context, materialpageroute(builder (context) => homescreen()), ); } else { scaffoldmessenger of(context) showsnackbar(snackbar(content text('sign up failed'))); } } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('chat app sign up'), ), body padding( padding const edgeinsets all(16), child column( children \[ textfield( controller usernamecontroller, decoration inputdecoration(labeltext 'username'), ), textfield( controller emailcontroller, decoration inputdecoration(labeltext 'email'), ), textfield( controller passwordcontroller, decoration inputdecoration(labeltext 'password'), obscuretext true, ), sizedbox(height 20), elevatedbutton( onpressed () => signup(context), child text('sign up'), ), ], ), ), ); } } 5단계 – 사용자 존재 구현 5 1 사용자 온라인 상태 업데이트 사용자의 온라인 상태를 업데이트하는 메서드를 authservice 에 생성합니다 // lib/services/auth service dart class authservice { // existing methods future\<void> updateuseronlinestatus(bool isonline) async { var user = await parseuser currentuser() as parseuser?; if (user != null) { user set('isonline', isonline); await user save(); } } } 5 2 로그인 및 로그아웃 시 온라인 상태 설정 로그인 및 로그아웃 메서드를 업데이트합니다 // lib/services/auth service dart class authservice { // existing methods future\<parseuser?> login(string username, string password) async { var user = parseuser(username, password, null); var response = await user login(); if (response success) { await updateuseronlinestatus(true); return user; } else { return null; } } future\<void> logout() async { await updateuseronlinestatus(false); var user = await parseuser currentuser() as parseuser?; await user? logout(); } } 6단계 – 연락처 목록 표시 6 1 사용자 서비스 생성 다음에 user service dart 를 생성하십시오 services // lib/services/user service dart import 'package\ parse server sdk flutter/parse server sdk dart'; class userservice { future\<list\<parseuser>> getallusers() async { final querybuilder\<parseuser> queryusers = querybuilder\<parseuser>(parseuser forquery()); final parseresponse apiresponse = await queryusers query(); if (apiresponse success && apiresponse results != null) { return apiresponse results as list\<parseuser>; } else { return \[]; } } } 6 2 홈 화면 생성 // lib/screens/home screen dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import ' /services/user service dart'; import ' /services/auth service dart'; import 'chat screen dart'; class homescreen extends statefulwidget { @override homescreenstate createstate() => homescreenstate(); } class homescreenstate extends state\<homescreen> { final userservice userservice = userservice(); final authservice authservice = authservice(); list\<parseuser> users = \[]; parseuser? currentuser; @override void initstate() { super initstate(); fetchusers(); getcurrentuser(); } void getcurrentuser() async { currentuser = await authservice getcurrentuser(); } void fetchusers() async { var allusers = await userservice getallusers(); setstate(() { users = allusers where((user) => user username != currentuser? username) tolist(); }); } void logout(buildcontext context) async { await authservice logout(); navigator pushreplacementnamed(context, '/'); } @override widget build(buildcontext context) { return scaffold( appbar appbar( title text('contacts'), actions \[ iconbutton(onpressed () => logout(context), icon icon(icons logout)), ], ), body listview\ builder( itemcount users length, itembuilder (context, index) { var user = users\[index]; return listtile( title text(user username ?? ''), subtitle text(user get('isonline') == true ? 'online' 'offline'), ontap () { navigator push( context, materialpageroute(builder (context) => chatscreen(receiver user)), ); }, ); }, ), ); } } 7단계 – 실시간 메시징 구현하기 7 1 라이브 쿼리 클라이언트 설정하기 다음 종속성을 추가하세요 pubspec yaml dependencies flutter sdk flutter parse server sdk flutter git url https //github com/parse community/parse sdk flutter git ref master 이것은 live query 지원이 포함된 최신 버전을 사용하고 있음을 보장합니다 7 2 main dart 에서 live query 초기화하기 // lib/main dart void main() async { widgetsflutterbinding ensureinitialized(); const keyapplicationid = 'your application id'; const keyclientkey = 'your client key'; const keyparseserverurl = 'https //parseapi back4app com'; const livequeryurl = 'wss\ //your app back4app io'; await parse() initialize( keyapplicationid, keyparseserverurl, clientkey keyclientkey, autosendsessionid true, debug true, livequeryurl livequeryurl, ); runapp(myapp()); } 'your app'을 'your app' 로 바꾸세요 7 3 채팅 화면 만들기 // lib/screens/chat screen dart import 'package\ flutter/material dart'; import 'package\ parse server sdk flutter/parse server sdk dart'; import 'package\ uuid/uuid dart'; import 'package\ image picker/image picker dart'; import ' /services/auth service dart'; import 'package\ cached network image/cached network image dart'; class chatscreen extends statefulwidget { final parseuser receiver; chatscreen({required this receiver}); @override chatscreenstate createstate() => chatscreenstate(); } class chatscreenstate extends state\<chatscreen> { final authservice authservice = authservice(); parseuser? currentuser; list\<parseobject> messages = \[]; string chatroomid = ''; final texteditingcontroller messagecontroller = texteditingcontroller(); late parselivelist\<parseobject> livemessages; @override void initstate() { super initstate(); getcurrentuser(); setupchatroom(); } void getcurrentuser() async { currentuser = await authservice getcurrentuser(); if (currentuser != null) { setuplivequery(); } } void setupchatroom() { string userid = currentuser! objectid!; string receiverid = widget receiver objectid!; chatroomid = userid compareto(receiverid) > 0 ? '$userid $receiverid' '$receiverid $userid'; } void setuplivequery() { querybuilder\<parseobject> querymessages = querybuilder\<parseobject>(parseobject('message')) whereequalto('chatroomid', chatroomid) orderbyascending('createdat'); livemessages = parselivelist\<parseobject>( querymessages, listeningincludes \['sender'], lazyloading false, ); setstate(() {}); } void sendmessage({string? content, parsefilebase? imagefile}) async { var message = parseobject('message') set('sender', currentuser) set('receiver', widget receiver) set('chatroomid', chatroomid) set('content', content ?? '') set('image', imagefile); await message save(); messagecontroller clear(); } void pickimage() async { final picker = imagepicker(); final pickedfile = await picker pickimage(source imagesource gallery, imagequality 50); if (pickedfile != null) { var file = parsefile(file(pickedfile path)); await file save(); sendmessage(imagefile file); } } @override void dispose() { livemessages dispose(); super dispose(); } @override widget build(buildcontext context) { if (currentuser == null || livemessages == null) { return scaffold( appbar appbar( title text('chat with ${widget receiver username}'), ), body center(child circularprogressindicator()), ); } return scaffold( appbar appbar( title text('chat with ${widget receiver username}'), ), body column( children \[ expanded( child parselivelistwidget\<parseobject>( query livemessages, reverse false, lazyloading false, childbuilder (context, snapshot) { if (snapshot failed) { return text('error ${snapshot error}'); } else if (snapshot hasdata) { var message = snapshot loadeddata!; var sender = message get\<parseuser>('sender')!; var isme = sender objectid == currentuser! objectid; var content = message get\<string>('content') ?? ''; var image = message get\<parsefilebase>('image'); return align( alignment isme ? alignment centerright alignment centerleft, child container( padding edgeinsets all(8), margin edgeinsets all(8), decoration boxdecoration( color isme ? colors blue\[100] colors grey\[300], borderradius borderradius circular(8), ), child column( crossaxisalignment crossaxisalignment start, children \[ if (content isnotempty) text(content), if (image != null) cachednetworkimage( imageurl image url!, placeholder (context, url) => circularprogressindicator(), errorwidget (context, url, error) => icon(icons error), ), ], ), ), ); } else { return container(); } }, ), ), divider(height 1), container( padding edgeinsets symmetric(horizontal 8), color colors white, child row( children \[ iconbutton( icon icon(icons photo), onpressed pickimage, ), expanded( child textfield( controller messagecontroller, decoration inputdecoration collapsed(hinttext 'type a message'), ), ), iconbutton( icon icon(icons send), onpressed () { if ( messagecontroller text trim() isnotempty) { sendmessage(content messagecontroller text trim()); } }, ), ], ), ), ], ), ); } } 설명 parselivelistwidget 실시간 쿼리 업데이트를 듣고 데이터가 변경될 때 다시 빌드하는 위젯입니다 sendmessage() 텍스트 메시지 또는 이미지를 보냅니다 pickimage() image picker 를 사용하여 이미지를 선택하고 메시지로 보냅니다 setuplivequery() 채팅방에서 새로운 메시지를 듣기 위해 실시간 쿼리를 설정합니다 8단계 – 앱 테스트 8 1 앱 실행 터미널에서 다음을 실행하세요 flutter run 8 2 테스트 메시징 두 개의 장치 또는 에뮬레이터에서 앱을 엽니다 다른 사용자 계정으로 가입하거나 로그인합니다 한 계정에서 연락처 목록에서 다른 사용자를 선택합니다 메시지와 이미지를 전송합니다; 두 장치에서 실시간으로 나타나야 합니다 결론 축하합니다! back4app을 사용하여 flutter에서 실시간 채팅 애플리케이션을 구축했습니다 이 앱은 다음을 지원합니다 사용자 인증 안전한 로그인 및 가입 실시간 메시징 라이브 쿼리를 사용한 즉각적인 업데이트 사용자 존재 온라인/오프라인 상태 추적 미디어 공유 이미지 전송 및 수신 메시지 기록 채팅 메시지 지속 다음 단계 그룹 채팅 그룹 대화를 지원하도록 앱을 확장합니다 메시지 상태 읽음 확인 및 입력 표시기를 구현합니다 푸시 알림 앱이 백그라운드에 있을 때 새 메시지에 대한 알림을 보냅니다 프로필 사진 사용자가 아바타를 업로드할 수 있도록 허용합니다 보안 강화 acl 및 역할 기반 권한으로 데이터를 보호합니다 추가 리소스 back4app 문서 https //www back4app com/docs flutter용 parse sdk 가이드 https //docs parseplatform org/flutter/guide/ flutter 공식 문서 https //flutter dev/docs parse 라이브 쿼리 https //docs parseplatform org/js/guide/#live queries 행복한 코딩 되세요!