Building a Realtime Chat App in 35 Minutes (Swift UI 2.0 and Firebase)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Does it include sending media like photos & videos?

👍︎︎ 1 👤︎︎ u/uV3324 📅︎︎ Oct 22 2020 🗫︎ replies

Does it include multiple users logged in at once?

👍︎︎ 1 👤︎︎ u/react_noob 📅︎︎ Oct 22 2020 🗫︎ replies
Captions
[Music] building a real-time chat app was once a weeks-long development endeavor however thanks to firebase and swift ui building an app with authentication and real-time data becomes trivial since the sdk takes care of state management and client data syncing for you in fact it becomes so easy i'll show you how to build a real-time chat app in less than 35 minutes if you're new to my channel please make sure you like and subscribe and without further ado let's get started so let's get started by creating a new xcode project uh you could call anything you want i'll call mine tutorial because i'm creative for the interface select swift ui and then for the app lifecycle also select swifty y app instead of ui kit app delegate you can go ahead and leave core data unchecked and click next then click create awesome so now that we've created our xcode project we could go ahead and configure our firebase project all right so before we get set up our firebase project we need to grab our bundle identifier which is a unique string found in our project settings that identifies our app to firebase so copy that and then we're going to open up the firebase console and then we're going to create a new project disable google analytics because we're not going to need it for this project then create the project all right so now that our project has been created uh click on this ios icon under the project overview to register our ios app with firebase paste in your bundle identifier and then click register app so now download the config file and then drag this into the root of your xcode project all right so now that we've added the firebase config file to our project we actually need to add the firebase dependency so we're going to go ahead and close out our xcode project and open up terminal we're going to cd into the xcode project directory where you have your um project stored and then you're going to run pod init to create our pod file so once your pod file has been created you can go ahead and open it and we're going to add two pods in here we're going to add firebase off and we'll add firebase firestore these are the only two pods we're gonna need for this tutorial so go ahead and save it and close it and then we could run pod install to install the dependencies awesome so now that we've installed our dependencies we need to open the project using this xc workspace file generated by cocoapods and instead of using just the xcode project file so you can click that and it'll open up our project now we have firebase installed on our app so in our app file which is just your project name followed by app.swift we can go ahead and import firebase and inside of our apps initializer we can just go ahead and run firebase app.configure which will automatically pull the data from our google service info.plist file and load it into firebase and connect with the firebase server [Music] alright so now that our project's all set up and we got firebase configured we can go ahead and start working on the authentication so we're going to create a new folder and i'm going to call this util and i'm just going to use this to keep all of the files that are responsible for fetching data and interacting with firebase so i'm going to create a new swift file called session store dot swift all right so in this file let's import firebase authentication and let's get started by creating our user model so our user model is gonna have two properties both string types the uid is simply the firebase identifier for the user and email is obviously the user's email after we created our user model we can get started creating our session store observable object our observable object is gonna have two published properties the session properties of type user and it's gonna just hold our user model if it's defined it's of the optional type since it could be undefined the other published property is anon is a boolean that will be true if the user is not logged in and it will be false if the user is logged in we will use this to to change the user interface depending on the user's authentication state since both of these properties are published it will automatically update the user interface whenever these values change all right so now let's create a variable called handle to hold our authentication state listener the reason why we're assigning this to a variable is so we could later on uh detach the listener when we're done with the view and finally i'm going to add a reference to the firebase authentication class so now we're ready to define our first function which is called listen when we call listen it will attach a listener the authentication state and firebase will use this listener to send updates whenever it changes so when we call the listen method on our session store it will attach a listener to the firebase authentication state and basically firebase will use this listener to send any changes to the authentication state whenever it happens so whenever the authentication state changes firebase executes this function and it passes an auth and user if user is defined it means that the user is logged in and we set isn't on defaults because the user there is a user so they're not anonymous and we set the session equal to a user object that we fill in with the values from the user object from firebase otherwise if the user object is not there which means they're not authenticated we set isn't on to true and we set the session to nil since there is no user all right so now that we finished that function we're going to define functions that we can call uh to sign in the user to sign up the user and to sign out the user all right so our sign in function is really simple it has two parameters email and password both a type string when we call the function with those two parameters we call the sign in method on authref from up here uh with the email address and the password uh it sends it to firebase to authenticate if it's successful our authentication state listener up here will um update the session and izanon uh properties our sign up function is really similar to sign in so we can just copy and paste it and this is just create user with email so and same deal cool all right so now we're going to write our sign out function it's a little bit different than sign in and sign up since we actually have to handle an error all right so basically our our sign out function returns a boolean depending on whether the sign out was successful or not so we could try to sign out and if it's successful it updates the session to make the user anonymous and it returns true on this boolean right here otherwise it returns false and actually i'm going to go ahead and update izanon appropriately to so the user is anonymous if the sign out method succeeds otherwise it just returns false on this finally we're going to define one last method on our session store and this is responsible for unmounting the authentication state listener basically we call this whenever we unmount a view so we don't have the listener running in the background when the user is not on that page alright cool so we finished our session store observable object so now we actually need to build the user interface to use it so we're going to create a screens folder and i'm going to create two screens so i'm going to create a new swift ui view and i'm going to call this chat list the chat list is going to be the main screen of the app and it's going to display all the chat rooms a user can access and then i'm going to create another screen it's going to be called login so our chat list screen is going to be the main screen of the app the login screen is going to be presented as an overlay if the user is not authenticated and it can't be dismissed unless the user signs in so i'm going to go to content view which if we look at our app view we can see that content view is like the uh only thing here i personally just like to do my changes on content view so we're gonna make the main screen of our app chat list we could call like that but we're gonna add the login screen as a full screen cover we're gonna set the content of our full screen cover to login so basically a full screen cover is like a modal except it can't be dismissed by a user it covers the screen entirely we're gonna make it so it's only dismissible if the is a non property right here is false right now we could see that the is presented property is set to constant true which means that it's just gonna be always open so let's go ahead and hook it up with our authentication so in order to access um our session store in our view i'm gonna create a new observed object and we're gonna set it to an instance of session store so now that we have that we could set is presented equal to session store dot is anon so now when is a non is false this full screen cover will be dismissed and the user could use the app as normal however when is it on is true the user is not logged in this will cover the app it ensures the user is authenticated before they send messages now that we have that in place we can go ahead and open our login view and do some work here i'm going to wrap our um login screen in a navigation view just so we could have the navigation bar title so let's let's go ahead and set the navigation bar title to set the navigation bar to welcome all right so now let's build out the interface we're going to use a v stack a vertical stack and we're just going to stack some text fields so the user can enter their email and password and password so now we can set the text property of our text field to be email and let's add some styling onto it just so it looks a little nicer and let's copy and paste that too we have a password field and for passwords we actually change this to secure field so now we need to create some buttons and finally we just hook these into our authentication so basically when we click these buttons for the action we want to call the sign in and the sign up method on our session store so let's go ahead and add a new observed object and set it to an instance of session store so now we're going to call sign in and we're going to pass the email and the password and we're going to do the same except we're going to change it to sign up all right so now that we've created our user interface and we're already all hooked in with the authentication let's go ahead and enable authentication on the fires firebase console so go to the authentication section and click on the sign in method tab and we're gonna enable the email and password provider click save all right so now that we've enabled authentication in the firebase console all we have to do now is call our authentication state listener the listen method on session store in the initializer of our content view we can call listen which should mount the authentication state listener onto our app so now we build it to my phone we can see if it works so this is our login screen and we can test it out so let's just put in a fake email i guess i don't think it matters sign up all right cool so our authentication state listener is working our full screen cover is working this though we're all hooked up with authentication so this is looking good so now that we set up authentication with our xcode project we're ready to get started fetching and storing data inside firestore to connect our xcode application with firestore i'm going to create an object that will handle fetching and putting data into firestore so i'm going to create a new swift file inside my util folder and i'm going to call this file chat rooms view model inside the chat rooms view model let's import firebase before we create our view model let's start by creating our chatroom model so let's create a new struct and call it chat room and it's going to be a type codeable and identifiable since we're going to be iterating over this object when we display it as a list so our chatroom model has three properties the id property which is of type string is gonna be the unique firestore identifier for the chatroom object the title is also a string and this is just gonna be the title field from the object and the third property it's called join code and this is going to be a random number we generate that other users can use to join our chat room so actually i'm going to go back to the firebase console and i'm going to add the join code field here and it's going to be a type number and click add so now we could use that join code to join our sample chat room so now that we've created our chat room model we can go ahead and create our chat room view model which is going to be of type observable object it's going to have a published property called chat rooms which will hold all of the chat room instances returned by firebase then i'm going to create two references one to the firestore database class and another to the current authentication user now i'm going to create a method called data when we call this method it will tell firebase to start streaming data from firestore to our application whenever the firestore data changes it will automatically send those changes to our application and update the chatroom's object and since it's published the user interface will automatically adapt to the changes when we call fetch data it will first check if the user is defined if the user is defined which means that the user is logged in it will go ahead and query the chat rooms collection in our firestore database for any documents where the users field contains the current user id the snapshot listener calls this function whenever we first call the fetchdata method and whenever the data inside firestore changes so we're first going to check if any documents return if there are documents returned we can go ahead and map over those documents and turn them into chatroom objects which we can then fill our published chatrooms array with so now that we've created our view model we can go ahead and set up the user interface for displaying our chat room list so if we go into our chat list screen which we created earlier let's get started by creating a list view so if we go into our chat list screen which we created earlier i'm going to get started by creating a new observed object property called viewmodel and i'm going to set this to an instance of chat rooms view model so now we could call fetch data on our view model inside of our chat list initializer which will attach the snapshot listener whenever this screen first appears inside of our views body we could change the placeholder text to be a navigation view and inside the navigation view let's go ahead and add a list to display our chat rooms so now that we created our list we can now um add a navigation bar title and now we can build it to our phone and see what it looks like okay so if we look on our phone we can see that it loaded in our sample chat room from firebase so our view model is working and it's fetching data appropriately and if we open the firebase console and we change this to be like test chat room we can see that the data instantly changes on our app and it automatically updates the user interface so this is looking great so right now a user is able to see a list of all the chat rooms that they're a part of however they currently don't have a way of joining or creating a new chat room so let's go ahead and implement that to do so we're going to add two new methods to our chatroom view model and these methods will be responsible for updating and putting new data into our firestore database so now let's create a new method called create chat room it's going to accept a title which is going to be a type string and a handler which is going to be a function that we can call um after the chat room has been successfully stored in the firestore database so basically our create chatroom method is going to check if the user is defined if the user is defined we're gonna add a document to our chatrooms collection in firestore and we're gonna set the title to be the title we passed into our method we're gonna set the join code to be a random number between ten thousand and ninety nine thousand and uh ideally you would want to use something a little more robust to ensure there's no collisions but for this tutorial i'm just going to go with this and finally we're going to initialize the users array with the current user id we're going to check if there's an error and if there is we're just going to print it to the console otherwise we're going to execute our handler we passed into our method now let's create another method called join chat room our join chatroom method is going to accept a code of type string and we're going to use this to look up a chat room to join in our firestore database and we're also going to pass in a handler which again we're going to call once or if the user successfully is added to a chat room we're going to check if the user is defined and if it is we're going to query the chat rooms collection and we're going to look for any documents where the join code is equal to the code passed into our method and we're going to turn this into an in since we are storing it in firebase as an end we're going to get the documents and if there's an air fetching those documents we're just going to print that to the console otherwise we're going to go through the documents returned by that query and we're going to add the current user to the user's field of the chat room and then we're going to finally call the handler function passed into our method so now that we set up our methods on our chat rooms view model we can go ahead and create the interface for joining a chat room so i'm going to create a new screen so let's create a new swift ui view and we can just call this join let's wrap this in a navigation view and let's add a title join our create looks good and let's go hook this up with the chat list view which is where we're gonna summon this screen so in our chat list screen let's add a button to the navigation bar and for our button i'm actually going to use an icon and to use 50y icons i just refer to the sf symbols application you could download from apple's developer website and i just find something ideal i think i'm going to use this plus circle so let's grab its name and we can use it in swift ui with the image and we just pass it in like this and now we're going to create a new state property and when we press this button we're going to set join modal to true let's add the join screen as a sheet to our navigation view so we're going to set the content to be joined and we're going to set is presented to be join modal so when join modal is true this sheet will come up and cover the screen and when join modal is false it will be hidden cool so now we can go to our join screen and get started laying out our interface so i'm going to create a v stack a vertical stack and i think i'm going to divide the page into two so i'm going to create two other v-stocks let's add a title without a text field and let's create some state properties to hold the value of our text fields and we can set the text property of our text field to be drawing code finally let's add a button and let's copy and paste this change this to create enter your new title we're going to change this to a new title all right so now that our interface is laid out and i'm going to actually add some padding to this so they stay kind of apart from each other so now we can add our chatrooms view model as an observed object and we're going to set that to an instance of chat rooms view model and we could call our methods that we added earlier so when we press the join button it will call view model dot join chat room uh we're gonna provide the join code state we'll leave the handler blank for now and let's do the same for the other button oh and i just noticed there's a typo right here so let's delete that uh let's set this to view model oops view model dot create chat room and we'll set that to new title so for the handler on both the join and create buttons we wanted to close this sheet once the action is successful so the user successfully joined the chat room or the user successfully created the chat room to do so we're going to need to create a binding to the join modal state in the chat list so to do so we're going to actually create a new property on our join screen and we're going to use the binding property wrapper and it's going to be a type boolean and we could just now go to our chat list and we can now pass is open and we put join mortal and we go here i guess that is open to dot constant true true so now in our completion handler we can just simply do is open yourself dot is open is equal to false so now when the chat room has either successfully created or the user successfully joins a chat room it'll automatically close this sheet and it will allow the user to see the chat list with the new chat room on it so now we can go ahead and test it out so i actually put my sheet in the wrong place so i'm going to put the sheet right below navigation bar items and then i'm going to move all of these from being attached to the list and i'm going to attach them to the h stack instead so a small mistake but quick fix and now we can see if the layout is fixed oh that rhymed there we go so we can see that the layout um doesn't have those weird borders anymore and if we press the plus button it shows our modal um the layout is not quite what i expected but it should work let's go ahead and try to create a chat room so we could call this new chat room create and we can see that new chat room shows up in our list and uh let's go ahead and go into the firestore console and create a chat room that we're not a part of so i'm going to remove the uid of the test user from the new chat room and we're going to see if we could join it click delete fuel and we saw that it instantly was removed from the list and let's see if we could join it so the join code is 37022 join and we can see it works so now we're able to create and join chat rooms so now that the user is able to see all the conversations they're a part of they're able to join chat rooms and they're able to create new chat rooms we're ready to create the message screen which is going to display all of the messages that are a part of each individual chat room so we're going to create a new view model and i'm going to create a new swift file and we're going to call this messages view model so let's just get started by importing firebase and let's create our message object which is also going to be of type codable and identifiable again because we're iterating over this object when we display it in the list view so it's gonna have three properties it's gonna have the id which is gonna be a type string it's gonna have the content which will be the string content of each individual message and finally we're gonna add the name property which is gonna be the name email address that we're going to display next to each message so now that we've created our message object we can now create our messages view model so i'm going to create a new class called messagesviewmodel and it's going to be an observable object i'm going to add a published property called messages which will hold all of the message objects returned by firebase and then i'm going to create references to the current user and the firestore class so now i'm going to create a new method called fetch data which will take in a document id string and we're going to use that document id to reference the particular chat room from our firestore database we'll store all the messages on a subcollection of the chat room called messages so basically when we call send message it checks that the user is defined and if it is which means the user is authenticated it adds a new document to the messages subcollection of the chat room documents on each message we add a sent out date which we can use to order the chat room in chronological order we have a display name which i'm just setting to email and we'll use this to display next to each method so we know who's sending what we'll have the content field which is again the message content string that we passed into this method and finally we have the sender which is just the user id of the current user so now that we finished that method we can now define our fetch data method which will take in the string doc id and we could use this to query the database okay so basically our fetch data method is similar to the fetch data methods we wrote on the other view model so basically we check if the user is defined and if it is again it means the user is authenticated we query the messages sub collection on the chat room which we use the document id we passed in to find and then we order those results by the sent at field which is the date we sent up here and we do it in descending order so the newest messages are at the bottom so we add a snapshot listener which again calls this function whenever there's updates on the data and if there's no documents it prints no documents and it just returns otherwise it maps the return documents into message objects and then finally it sets our message property up here or our messages property up here to be uh the documents returned and since it's published it will automatically update our interface so now that we finish our view model we're ready to create the user interface so let's go ahead and create a chat screen so i'm going to create a new file and then we'll create a new swift ui view i'm going to call this messages and now that we've created our messages screen let's go ahead and hook up the navigation between the chat list view and the messages view so on the chat list we're going to wrap our h stack in a navigation link so a navigation link will basically make our h stack tappable and it makes it act like a button and we can set the destination property to messages so when we tap the h stack it will now take us to our messages view and we could go ahead and pass parameters from the chat list to our messages which we're going to need to do since we need to know which particular chat room the user wants to see so i'm going to go ahead and define a chat room property it's going to be a type chat room and now we can go ahead and pass the current chat room in as a parameter and down here to prevent any errors we can go ahead and define a chat room to pass in here so now that we've defined our chat room property we can go ahead and set the navigation bar title to be the chat room title and we don't have to wrap this in a navigation view because navigation link uh pushes this view on the previous one um so it keeps this navigation view here so if we define a navigation view here it would kind of put a navigation view within a navigation view which is not what we want so this navigation bar will replace this navigation bar title over here so now we can add our view model as an observed object and we can initialize it with an instance of messages view model so now we can replace the text with the list view and we can pass in view model dot messages and we could pass the message content in to a text object so right now the user can see all of the messages in the given chat room however they have no way of sending a message so we're going to need to add a text field and a button at the bottom of the screen below the list where the user can enter their message and press send so to do so let's wrap our list in a v stack and below the list i'm going to add an h stack a horizontal stack so we can have a text field and a button next to each other we'll have the button say send and we'll have this text field say enter message and let's create a state property to store the text fields value and let's add some styling onto that text field and for the button action let's hook it up with the method we defined on view model so let's call view model dot send message and for the message content we could pass in the message field state and for the doc id we could pass some chat room dot id cool so we now put this on our phone actually before we build it we need to define our initializer so let's create the init method and we need to pass in a chat room and we need to set self.chatroom equal to chatroom and then we need to call viewmodel.fetchdata and let's pass in now let's build it to my phone okay so now we can see that there's an arrow on each row which means that this is tappable so we tap the chat room there's no messages in it right now but we could send a message so we could say hello and it just appears right there but yeah this works if this video helped you please like and subscribe for more tutorials and walkthroughs i know we could have added a lot more features and made the ui look nicer but this project is just supposed to be a starting point for any real-time swift ui apps you might want to build with firebase as always the code's in the description thanks for watching and i'll see you soon
Info
Channel: Nathan Luu
Views: 7,515
Rating: undefined out of 5
Keywords: Swift, SwiftUI, SwiftUI 2.0, Swiftui 2, iOS 14, Firebase, Firestore, Chat app, iOS Development, ios programming, programming, code, coding, swift, objective c, apple, iphone app, ipad app
Id: kV6aZ_vgykA
Channel Id: undefined
Length: 34min 48sec (2088 seconds)
Published: Wed Oct 21 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.