Kotlin Multiplatform Mobile: Make Cross-platform Movie app - Part 1 Shared Code

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody now my goal in this video series is to show you how you can use cotlin MTI platform technology to build a simple uh movie application for Android and iOS uh you can see on my screen I've got on the right side my Android device and on the left side an iOS simulator I'm going to give you a quick look of what you can expect to create at the end of this video video series now let me take you first of all on the Android side you can see that we are fing movie data now on this home screen we are just displaying um popular movies retrieved over internet uh you can scroll or click on one item this will bring you to a detail screen um we not going to implement like this play functionality here sorry now I've also here on the iOS the same functionality you need just to click on one item to see the details of the film all right I want to mention a couple of prite here um the first of all is that I'm assuming you are in somewh familiar with cotl because this is not going to be like a complete beginner video tutorial so you should know for example why we using dependency injection and also assume that you know uh how the clean architecture and all that stuffs work and the other thing is that as per Apple requirement you need xcode like with a M Macintosh operating system uh to run your iOS application this has nothing to do with C multiplatform technology it's just Apple all right now before we get started I want to take a little bit of time to talk about the data provider we're going to use the API from the movie database. org I'll provide this link uh in the video description so in order for you to be granted an API key you'll need to create a free account uh it will it's is really simple and once you have created your account you need to come up here on your profile and click on settings uh scroll a little bit and at your left side you should see this API key you need to click that it will bring you on this page here so if you have ENT a key um they will like give you a link and ask you questions so they will grant you a key uh I've got here my API key and this is example an example of how you could make an API request and the next thing is to come up and click on and click on this link here um this is the API documentation I've got it already opened so uh I would suggest you to take a little bit of time and understand how uh how this API works and what kind of data are retrieved here we will we will use just to handpoint here uh this one to get the details about movie uh here is the base URL as you can see and we're also going to use um this get popular handpoint yeah just to get popular movies and display them in our home screen now to keep things simple we're just going to retrieve a few Fields here uh will not retrieve the page since we are doing the pagination s we'll need the poster path we'll need the overview we'll also retrieve the release date the ID and the title yeah I think that's all we're going to retrieve yeah just to keep things simple all right guys I've got here my Android Studio opened and we are ready to start creating our project now the first thing that you will need to do if you haven't already is to install the C multiplatform plugin and for that you need to come up here under plugins and you need to type uh cotlin M this should suggest you this cotl multiplatform mobile plugin you need to click on the install button that's going to download the plugin and install it in your Android Studio once this the installation is done you'll need to restart your Android Studio in order for you to find the C mobile multiplatform mobile template uh during the project creation after that you will come up here inside project Tab and you need to click on new project let me expand this a little bit so yep you need to scroll down until you find this template here theod multiplatform app you need to click there and click next so here you will need to set up the name the package as well as the location of your project so I'm going to name this as movies like so uh the package is good for me uh and also leave the default location after that you need need to click next now on this second page of configuration you would like to pay more attention to the dependency manager and as you can see here it says Coco dependency manager C multiplatform Used blah blah blah blah blah requires um Rubik Jam installation uh so this that this basically means that it requires you to do some extra steps you order for you to use the gooo dependency manager for our K application so I won't cover that extra steps that's why I Rec I recommend that you use this uh the regular framework as it says here doesn't require any third party tools now if that's not selected by fault you need to come up here and change that from yeah from cockoo to regular framework now you can leave these names and if it if this is U like checked by default you need also to uncheck this and after that you will need to click finish now this is going to of course take a little bit of time um to build um all and put all the files together now I'm going to skip the video Until the boot is done all right guys now the boot is done and the first thing that you would like like to do is to come up here change the view from Android to project now this way we got here all the files and directories of our project listed as you can see a c multiplatform project is a multi module project we've got here three modules the first one is this Android app as I got here this is just a normal Android application you can see that yeah if you're Android developer you would recognize this project structure over here we've got also IOS app this is as you can read an xcode project uh here is the project structure if you are Apple developer you would recognize this as well now the third one this the shared module is the one that normally should be new to you if this is the first time you work with C multiplatform application I'm going to expand this as you can see we've got here some kind of other modules now on one hand we have this one over here Android Main and then common Main and then iOS men these are code Source set now as per the documentation a short set is just a collection of cot code files along with the resources and the dependencies the first thing i' would like you to do is to come here under the sh module and click here on w.r. kts file you can see that I've got here uh a couple of things added also just to yeah to go quickly and I've got here the c x serialization inside this plugin uh you need to have this c x serialization plugin with its version this is just for data serialization and deserialization now if you scroll a little bit down you'll find uh this Source set block inside this Source set you'll find uh we've got common main now inside this common main I've haded a couple of dependency here I'll provide you the link to my giab repository that way you can grab this dependencies so that we get started quickly you can see I've had it here K dependencies uh c cortines as well as the coin dependency now after that you that's not all you need to scroll down until you find this Android main block um probably you won't don't find like with this by getting and dependencies already set up you will find probably this um Val declaration has Android men you need to hand all this also for the iOS you would like to have this dependency here you can see this is Kor client this internally will create an HTTP client engine specific for um the iros platform here as well for the Android client of Kor that will do all the almost the same thing now once you have had this dependencies you would click here on the sync Okay click here sync that is going to bit grle now this may take also a little bit of time so I may skip the video as well okay I think the the boot is done I'm going to close this come up here and expand my source set to go like quickly I'm going to delete these files because we don't need them you can hold command and select each one uh that way you can delete them the following problems were found yeah delete anyway uh okay so I think here we are ready to get started it oops I'm going first of all to create uh data directory for our data layer I will name this data now inside this data I will create a new directory I will name that remote I'll create here new C Class fine and I will name this movie remote uh this will be a data class and hit enter now in here I will declare all the feet that I would like to retrieve from the remote API on one hand that is the ID which will be of type integer I will also retrieve the title type string I'll retrieve the overview which will be yeah the description I would like also to retrieve the poster image of type string and lastly the release date now if you read the documentation like you should have seen that this release date here is not spelled like with this with the Cel case instead they have written it with Al already now I would like a way to tell the the c x ination that okay you're going to read this fed like like this but we want you when um dzing data to return this uh to use the D like yeah in Comm case so for that we need to add one annotation here and that is serial name so in here we're going to write a string value that tells uh here is how you will read on the feed from the remote data source I'll write here uh release dat we need to do the same thing here for the poster image I'll have here serial name oh sorry serial name and poster pu oops poer paff like so I need also to hide here The annotation serializable yeah now we are also going to retrieve a list of data and for that I need one more model here that represent a list of uh this remote um movie here and for that I would come up here under remote and create new Cod class fine and I will name that movies response like so oh not responses this is also going to be a r class and this will contains uh one feed and that is results which will be a list of movie remote like so uh this is correct if you looked at the get popular handpoint they return an array called result which will contains all the movies now we don't need to add any annotation for this that's good now next thing is to create um our Kor API I'll create an abset class uh to set up the HTTP client come up here on the remote create a new coding classified and I will name this CER API you can hit enter here oops I forgot one thing I should also had an annotation here U this realizable like so all right so this is going to be um an internal abstract class Kor API now I've had this internal keyword uh for like optimizing on the iOS side because because this this will tell the native codling compiler that it should not yeah of course this internals um prevent from exposing this um to other modules but also the internal keyword will limit the number of objective c adapters that the native uh codling compiler has to generate uh I need I'll will have also I need also to add this here as internal because all these classes are not going to be exposed to the external word so I'll come here I need to paste two things here on one hand the Bas URL and the API key after that I'm going to declare the client the HTTP client and initialize it with http client use this we've got here an HTTP client configuration and for the configuration I'm going to install the content negotiation as uh Json configuration in here I will call the Jon o oops Json from content negotiation config and I would need the disent Builder let me see yeah this this first one over here and for the configuration I would say ignore unknown keys to True uh use alternative names equals false now this is like a basic setup of HTTP client let me close this now next I need to create an extension method to the request Builder HTTP request Builder that's way we can like set up some of the common um URL configuration I'll come up down here and I will create a new function it will be an extension function to the HTTP request Builder I will call this puff URL now this is going to take a puff like for each end point it should like provide the like for getting like popular movies we provide here uh movie SL popular and for getting a single movie we provide here for the pa uh movie SL the movie ID now inside here I will set up uh I will call the URL request like the eural breeder here function um the eural breed there yeah in here I'll first of all set the B URL by calling the take from method take from method and writing inside here the Bas Ur that have declared on top of this file after that I would like to set up the puff uh this one here and since we are using the third version of the movie database. org I also had this path over here as well as the path that we received I've had one parameter that is common to everybody and that is the API key API key had API key over here so right I think this is done for our cator API the next thing that I would like to create is a movie service and I'll come up here under the remote create a new cing class fine and I will name that movie Service uh it will be a normal class let me have the internal keyword as well this will extend the cator API abstract class that we have created API like so oops sorry so in here I'm going to Define two suspend method to call um to use the client from the cator API that we have created to retrieve data actually one hand I will have this suspend function get movies which will retrieve all the movies from the popular endpoint um would like to to pass here a page as integer since you're going to do um pagination and I will initialize this to one if there's no page um given and I will call the client get method um this the second one over here the get method is also a suspend function that's reason why we needed to declare this with suspend keyword so in here I will set I will call the PA URL because this as you can see uh gives us an HTTP request beer so we can call the extension function that we have created earlier and set here our end point Which is popular slash movie oops movie SL poopular and also this should return um sorry this should return our movies response now i' would like also to have here one parameter the parameter is what am I writing par yeah parameter and I will have that as page passing in the page that received and finally call the body method to convert um the response that we receive into this uh movies RIS now the next one is a method to get a single movie I'll call this get movie this need a movie ID as integer also it should return movie remote single movie and I will call client. get where is the meod now right over here and I will set the path Ur all to movie slash I need uh string interpolation and pass in the movie ID and after that I call the body method to convert that to movie remote now the next next thing that would like to create here is a remote data source now a remote data source is a class that will be responsible uh first of all to provide the remote um the remote data to the repository as well as switching our Network hold to a background thread I would like to have some sort of control on which um background thread I'm I'm going to execute my network call now as Android developer we like to use um the dispatcher IOU for all the reasons that you guys know and we don't need to do any sort of compromis comprom so we don't need to do any sort of compromises here now what we need is a way to tell km that hey okay I know that I'm writing shred code I'm inside the shred module but still I don't need to do any sort of compromises here I would like like when we are under the Android platform I want you to use this dispatcher IO and whenever we're not in Android platform yeah I'll provide you something else that you can use thanks to the expect actual mechanism of cing multiplatform that possible and that main reason that you see here we've got Android men as well as iOS men so whenever you you are you need to use some platform specific API you just need to use the expect actual mechanism to tell km that okay here is uh what I would like to use for Android I don't want you to do yeah to use things that I don't need here now I'll come up here and close this remote close the data and inside our package I'm going to create a new directory I will call this and inside this U I'll create a new Cod class fine and I'm going to name this dispatcher select fine now in here I will create an internal interface called dispatcher this will set up all uh the dispatcher that I would like to use for my networking so I'd like to use an iio dispatcher for when I'm using Android and I would like to use a dispatcher when we are using the iOS platform so I declare here a Val IO that should be a cortin dispatcher like so now to tell km that hey I need this dispatcher to be platform specific you'll need need to use the expect actual mechanism I'll declare here an internal function internal expect function pay attention to this expect keyword here because um this is what doing all the magic let me finish writing this fun provide dispatcher this should return a dispatcher the one that have created as you can see uh km is already complaining saying that okay now you have taugh me that I need to go in uh inside each platform and find a way to provide this dispatcher here but you haven't created it uh anywhere so next we'd like here to to provide the dispatcher for when we are using Android and for that you will let me close this that was not a good explanation and you need to come up here inside Android Main in our Movie package we need to create the a directory or package and we going to call that util this needs to much like this path here needs to much uh for the km to find this dispatcher you need also to give like the same path here so I'm going to create a new file and and I will give it the same name as dispatcher I will select fine and in here I'll create an internal class code Android dispatcher like so this will implement the dispatcher um interface that we have created and then provide uh the IU cting which is going to be dispatchers using the dispatchers from C cortin iio for end rate and in here I'll declare an internal actual now not expect but actual function provide dispatcher and should return the dispatcher as an Android dispatcher like so we need to do the same thing here uh under iOS main let me expand this create a directory new directory I'm going to call okay youtil as well and in here I'll create a new cing class file name dispatcher so I'll create here an internal class uh called iOS dispatcher this will uh Implement dispatcher and provide the iio dispatcher as dispatchers do you can see that there's no IOD uh like there's no how you suggest it here because the codling multiplatform knows that hey here we're not going to use any Android uh platform API code now what we' like to use here is this default cortin dispat whenever we using uh whenever we are inside our iOS platform all right so I will need also to provide an internal actual function provide dispatcher you need to name it the same way uh using the same signature just replacing the expect by the actual need return the dispatcher as iOS dispatcher here now you can see that yeah it's happy now saying okay now I know how to provide this dispatcher right here uh let me close this dispatcher creation here I hope that you understood what I've tried to explain you here through this example of using uh a specific dis dispatcher when using Android or iOS now the next thing that we like to create here let me first of all close this the Android and iOS main I will come inside our data package inside remote create a new cing class file and I will name this uh remote data source data source it will be a class all right uh let me also add the internal keyword right here like so this will need an instance of our movie service going to add this here API service movie Service as well as uh what else yeah the dispatcher we have created so far uh well dispatcher at didn't even have the dis uh the Val key word here we didn't have that so like I said this remote data source here is responsible for providing the remote data to the repository as well as uh switching the network hold uh to a different thread using the dispatcher we have um we need to to get here as dependency now have here a suspend function get so this a suspend function yeah um suspend function get movies with a page integer now this will call the with context from cod in cting and I will use this pat. iio and from in here I call my API service to ask for movies passing in the page as page uh next is a method to get a single movie get movie what am I writing this need a movie ID and will switch it to an IU context and then call Api service get single movie this one passing in our movie ID as movie ID now the next thing I would like to do is um to create a domain layer so I will create here um a new directory actually I'll name this domain and inside my domain I will would like to create a new directory um code model inside the model is where we're going to create our movie movie data class that represent a movie um inant that we like to show in our UI so we're going to have here pretty much the same fade as in our remote movie except that um this this class here won't have any kind of annotation and will not be related to any sort of data manipulation now I have you an ID I type inter oops of type integer will need a title I'll type string I will name this not as overview but as description yeah so I will also need to have here um what again image URL yeah I will change also the name here because uh this is much more descriptive and lastly I will have here a release date which will be of time string now this is the kind of data that we receive from our remote API uh uh and we'll need to instead in our UI we will use this movie uh data class here now we need a way to pass the data from the data layer to The Domain layer uh for that we use what we call mappers which are just extension functions that helps mapping uh data from one layer to another so I will come up here inside my data package close the remote going to create a new directory called um util yeah let me also name this one utils uh I will create a new file here C Class file and I will name this my par where I'm going to declare extensions functions to M data from the remote um from the data layer to The Domain layer so in here I we create a first mapper and the only one that we going to use uh in this course because this is not a big project so I'll create here an internal function uh code like so call this to movie this will return movie from our domain layer need just to create a new movie for the I so for the ID you're going to take the ID uh for the title you're also going to take the title or the description you will need to provide me the riew for the image URL now comes now comes one thing if you read the documentation you would see that the poster image that we are retrieving here is not the entire image URL but just the last part of the image Ur So you will need here to create an Al method I will name this like um private function get image Ural um provided that we got here a poster image uh get image Ur actually now this will return a URL starting with h https and this is going to be the image do D Movie Database dot or SLT SLB SL here we need to precise quality and then attach the poster image we have received here now I need to call this from here and get image Ur passing in the poster image and for the release date we just need to pass in the release date so next we'd like to come up here inside our domain I'm going to create a new directory called repository I'll create a repository a movie repository into face uh movie repository oops and this should be an interface hope that I see everything good so in here we're going to declare two suspend function on one hand they get movies which will take an page as well and return a list of movie not remov remote part movie this time uh not that's not all we need also another suspend function get single movie oops not the page but the movie ID and returns just movie all right um yes now we need to give an actual implementation of this movie repository for that we create another repository now inside our data layer here inside our data directory I need to create one more directory that is called repository so we need to create like an interface here and an actual implementation here and that way we can also make test um pretty much quick by by giving just fake implementation of this repository so I'll create here uh repository implementation class I'll name this movie repository repository implementation yeah like so this also will be an internal class internal class even this needs to be internal uh internal interface like so and this will Implement our movie movie repository actually and then provide the get [Music] movies overwrite this get movies oh what's happened uh get movies yeah like so and yeah this needs sorry this actually need an instance of our movie remote data source private B remote uh data source so what's what's going on CL is not abstract and doesn't not Implement abstract yeah we're going let me just quickly have the second method over here so we'll next um need from here see we are not going to implement uh the cash layer uh we'll just need to call our remote data source not get movies and then passing the page what's going on yes uh we need to mop this let me first of all oh what's going on use the result and yeah and map it it to movie Next so I will also need here to call uh to return first of all remote data source now get single movie passing in the movie ID as movie ID and call this to movie this extension method that we have created so far uh I I I can see that my vory is low uh let me plug in here my my power power supply all right so next we need to create our use cases I will come up here um where close the data now inside the domain I'll create a new directory called use case and inside this use case directory I'm going to create a first use case and that is is get movies um use case like so should be a class um this not going to be internal but it needs to be a coin component now I'm using the coin component here that's way I can directly inject like The View on the repository inside this get use cases because in the I side we don't have any way to inject instance is so I'll declare here um private Val repository um it should be it should be movie repository and I can use here buy inject to get an instance directly here you need to import that I would like here to normally uh over write invoke operator so I'm going to declare this as suspend operator function invoke like so uh I should pass in page and this uh will return a list of movies I would like here to keep things simple and for that uh I would just return uh our repository that get movies passing in the page page now you need to add this um add through exception yeah okay now this Pro exception um will just tell the Swift file that this invoke method here might throw exceptions for example if you don't have internet connection but I don't want to go dep inside her handling I'll just to catch here whatever uh whatever exception is from here through this uh Global exception class and that's it for this get movies use case I'm going to create another use uh use case here and that is a class to get a single movie get movie use case it will be a coin component let me quickly declare my repository repository as mov repository my inject need to import that and suspend operatory function invoke this need a movie [Music] ID and this will return a simple movie call the repository. get movie pring in the movie [Music] ID oh we forgot the return the return keyword and also need to have this throws exception exception class all right so the last thing that we'd like to do in this short module is to set up our dependency injection so uh let me close this coming inside of Movie package I'm going to create a new directory called Di and inside that di directory I'm going to create a new cing class F and we will name this uh shared modules so in here just to keep things organized um I often decide to create this like per layer module so first of all I will uh declare this private W uh oops what am I doing private Val data module for all all um for all Dela related um classes so I need to call on the module over here and then for like let me show you inside the remote we would like to provide uh the remote data source as well as the movie service yeah this one over here what we going to use the factory method of coin this Factory um just will create a new instance each time that we need like for our remote data source remote data source so since remote data source also need um API Service as well as the dispatcher we are going to tell coin that okay I'll I'll provide you these um dependencies as well by calling the G the get um method we also need so we also need um Factory for our movie movie service um this need no parameter so we'll need one more here and that is for the utility module uh module here and this is just to get our dispatcher provide dispatcher yeah ins meod uh that's all for the utility we also need one for our domain so um in the domain you like to provide our repository and we need uh a single instance for like the whole lifetime of our application we'd like here to get a single instance of our movie repository and here I will actually call the implementation movie becauseit implementation and then get the remote data source let me see if that's all we need to do nope we need also to provide uh like use cases Factory uh get movies use case and here also Factory foret single movie use case I think that's all we need to provide here okay next I would like um let me close this next I would like to provide um next I would like to create here a list uh private Val shared module module modules it's a list of all the shared modules the main module data module utility module and here provide and help a function to get sh modules this will just return the list that we have created that's way we will call just this function here whenever we want to to to start our coin yeah so I think this is all for now uh this is all for the shared module now in the next part we are going to implement the Android Y part this is a new channel uh if you like the video you can give us that thumbs up and also don't forget to subscribe to the channel I'll be posting um more recreational content especially about the codling multiplatform mobile if this is a topic that interest you uh don't forget to subscribe also because uh a second part and a third part are coming uh as soon as possible so I'll find you I'll see you in the next part for now take care
Info
Channel: Mr Dip Coding
Views: 23,462
Rating: undefined out of 5
Keywords: Kotlin, Android, iOS, Kotlin Multiplatform Mobile, SwiftUI
Id: zHrXSWBH3Ms
Channel Id: undefined
Length: 53min 18sec (3198 seconds)
Published: Fri Feb 17 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.