Video details

Bringing Your Angular Web App to Native | Mike Hartington | ng-conf 2022 Webinar


So, you have a killer Angular app you've built and want to take it from your web browser to the App Store. Sure, there are a lot of options here, but most will require you to maintain separate apps for each platform. You want your codebase to be as close as possible across Web, Android, and iOS. Thankfully, with Capacitor, you can take your existing web app and quickly create native iOS and Android apps for distribution on your favorite App Store!
ng-conf is a three-day Angular conference focused on delivering the highest quality training in the Angular JavaScript framework. 1500+ developers from across the globe converge on Salt Lake City, UT every year to attend talks and workshops by the Angular team and community experts.
Follow us on twitter Official Website:


Thank you all so much for joining and having a good time with us so far. I've been having a great time. This has been so much fun. We're going to be talking about some cool stuff today. Okay, I will preface this where I got a couple of chat windows open and I got two displays. So if you see me looking left and right, it's not that I'm looking all over. I'm trying to bounce between what is chat, what is slides, but with all that said, we're going to go over how to bring your Angular Web app to native and use a little project that my team's been working on called Capacitor. My name is Mike Carlton has been established. All right, can we get a confirmation for audio? Good to go. All right, well, I don't know what happened there, but we are going to go with headphones and hopefully that works. Well, thank you all for letting me know that we lost audio. Okay. Yeah, like we said, this will be recorded. So in the case that there is some audio issues, don't worry, we'll be able to replay this. I'll try to provide the slides and the app that we will be building afterwards. So more incentive to follow me on Twitter. And I will be going through the Q and A afterwards, so post your questions there. So starting off, we're going to be talking about this idea of cross platform development. This isn't a new idea. This is something that's been around for quite a bit and it's actually the de facto way of building video games. So if you ever have played a modern video game, chances are you are playing a game that's been built on something like Unreal Engine Unity. Bunch of proprietary cross platform game engines. Really fun. One that I like is if you've ever played a video game, Metal Gear Solid, they built their own engine and they called it the Fox Engine, which I think is just such a cool name. But these cross platform engines are ways for you to go ahead and build something once deployed to all of these different platforms that you want to target. Mobile development has a similar approach, but for some reason it's not necessarily the go to way for developing, especially for native. Now, the goals across platform are fairly simple. Reduce the amount of knowledge that you need to build something and deploy it to those various platforms. Reduce the amount of code that you need to write and maintain. Especially important these days as code complexity tends to increase. We want to make sure that we're focusing on whatever it is that we need to do versus having to worry about these minute details and then all in all, trying to figure out the best way to reduce the amount of time needed to deploy an app. So all pretty simple goals and I think cross platform tends to do these really well. Now, when comparing cross platform, we should probably think of these less as what is one being better than the other and more on what level of an abstraction do they operate at? Pretty simple. If we were to think about a scale where we have a pure web app on one end and then a pure native app on the other, where do our cross platform solutions fall into this spectrum? So, with that in mind, just do a quick little comparison of some cross platform solutions that exist nowadays. One of the first ones that we'll look at is this one called Cordova, and you probably have heard of it as the name phone gap before. It is probably the first cross platform mobile app solution that has ever existed. I believe it was created shortly 2008 after the first iPhone SDK was released. And they really have this goal of being a polypell for the browser and eventually to cease to need to exist. They wanted to disappear after the browser got good enough, where they added features like camera file system, geolocation based on proposals and web standards, and they would implement them. So that way when those standards finally shipped, they could deprecate their plugins and their APIs and just use whatever the web promised. That didn't turn out the way that they intended. So they ended up having to just for a longer while. But they got APIs like this, where they would create this camera object on the Navigator and it would have a method called Get picture. It followed this format where it would have an onsuccess callback and on sale callback, and then a final argument of how we want to configure this camera object or this instance of a camera, and we would be able to get some data back from it in our own success callback. And then a message whenever something failed. What stood out to me about this approach is that it is very limiting in terms of being cross platform. This API is only ever going to be available in an environment where Cordova exists. And eventually the API just never caught up to what the browser standards ended up producing, which is the media device API. So we got in a situation where this API existed for a long time and it only existed in a cordova realm where people were having to be forced to work with these limitations. So the API was not as cross platform as intended, and it had to create a lot of things that we take for granted for now. Had to create its own package manager, it provided its own build scripts using, I think at the time, various make files, bash scripts long before NPM hit the main stage. So it was not as great as it could have been. But for the time, it did a lot of great things. Tried to polyfill the web, tried to hide away from the fact that we needed a native IDE and it tried to make sure that we could just blow away our native projects and only treat them as a dis target. That way, when we did her build, we just got the IPA or the APK as an output. Moving on to the other end of the spectrum, something furthest away from the web and maybe one degree separation from pure native is this compiled native idea. Now, there's various projects here that could fall into a solution, so I'm not going to list them all, but we're going to look at one code example which will be pretty obvious to what it is. But their ideas were writing once for all, these platform doesn't work and it can never work because these platforms are so different. Instead, we should have an API that allows you to learn one approach and then have multiple code bases where you can swap in per platform implementations as needed. So that's their approach. And they promised this idea of a truly native app, which doesn't actually it's not actually the case and they actually did some really good things. Their abstractions around native controls really meant that people were working with platform primitives. Distracted as they are, they were still rendering platform specific controls that folks would get used to. And they provided a really nice standard library around coordinated APIs. So if you wanted to get access to the camera or create your live camera feed and embedded inside of a view, you could do that. Their architecture was actually not too dissimilar from how phone app operated, but what they had at the Sense was that your web app would be run in some sort of runtime. This could be V Eight, this could be JavaScript core on iOS, or it could be its own custom renderer altogether where everything is done inside there. Then from that custom renderer or that custom engine, we're sending things out to this bridge layer which would call in the appropriate OS and hardware features and then serialize the data back. So this architecture is actually pretty similar between all platforms. It's not too unique to one or the other. Now where this could break down is having to learn the different syntax and languages for each approach. I don't know about everyone here, but when I am told this will be the best project ever, all you have to do is learn a brand new language and a brand new ecosystem and learn the quirks of that platform in that language. I'm already checked out. You've already lost me at having to learn yet another language. I just want to build something and ship it. If you have to go ahead and incorporate some features that already exist in the web app, you're going to have to recreate them. For these compiled and native solutions, there is no web interrupt at the moment and most likely there won't be because of how they're architected and how they're built. So I can't grab features that already exist inside my web app, just drop them into my project because I'm writing probably some form of custom JavaScript that renders swift controls or some other language that renders custom drawn controls. And then in the third party realm, there's very limited libraries that are available to us. So if you're trying to look for say, a canvas API or library, unless you're willing to use one that exists, unless you're willing to write one for those per platform implementations, you're probably out of luck. Whereas the web has dozens of libraries out there that all do the same thing and you have choice of galore. So it's not all it cracks up to be, and it's not all sunshine and rainbows and it's compiled to native land. And this truly native bit to me is very peculiar. And it's a weird thing to sell because you're not necessarily rendering something purely native. In some implementation you have a JavaScript VM that will interpret your JavaScript and call the correct native code to render your controls essentially on the fly, which sure, you could say, well, the controls are native, but most of your app logic is still operating in JavaScript. And in other implementations where you have a fully custom renderer and a fully custom language, they're not using the controls that are per platform, they're creating their own controls and just essentially drawing them on the screen when they are needed. So this idea of something we truly native is, I think, a terrible thing to kind of highlight. It doesn't really mean anything, especially to me, and it shouldn't really mean anything to you because what is really native these days, it's kind of a moot argument to really have. So we kind of talked about one degree separation from the web, one degree separation from purely native. What happens to you right in the middle in this case, that is this project called Capacitor. Now, Capacitor is a great project that we've created at Ionic, but it is not tied to anything that we do. It's framework agnostic is library Agnostic. It's truly just pure JavaScript library that you can use in any app. So it exists in two parts where we have this native runtime that you can use to embed a web app inside of a native control or inside of a native application. Now, to just do that would be very limiting. It might not actually be approved by certain app stores. So we have an API that allows you to bridge that web app and that native wrapper and call native features. So you could call Geolocation, you could call the file system Bluetooth, what have you. Anything that's available through native can be exposed to your web app. The API itself actually provides a different implementation per platform. So you're going to get one that exists specifically for the web, one that will exist specifically for iOS, and one that will exist specifically for Android. But you as a developer are only ever interacting with essentially a facade. Your API that you interface with is going to just call the correct behind the scene implementation and all you have to do is call something high level that knows, here are the options, handle the data however you need to. And for the tooling side, we're making use of the native tooling that comes with each platform. This means on iOS we're using things like Cocoa Pods and on Android we're using Android Library features which are all pretty awesome. So altogether, this kind of already feels like it's pulling in the best of both worlds. We're getting pretty standard native tooling, but also pretty familiar web developer environments. So I really like how that feels. Architecturally. This is very similar to that compiled a native solution where in Blue we have this web app that we are going to render. And then we have this native wrapper that exists and presents the web app to our users. From here we have a bridge layer that will interpret calls from that native rapper and then send us out to the appropriate system features. So it'll call any OS level features like getting the battery status or it'll call hardware features like presenting the camera or interacting with Bluetooth. Once those calls have been made, they'll serialize the results, pass it back into the wrapper, and then send that along to your web app to consume in the form of a promise. So this is a fairly straightforward architecture. How is it different from other solutions? Well, first and foremost, it basically lets you be able to take your existing web app and just load it up into a native context. Really great. The runtime and APIs are available instantly, so if you need to go ahead and have some very fast system calls or you want to initialize native crash analytics, you can do that in the native code and it's going to instantly be available. And if for some reason you are updating to a new version of your native Ide's and your native tool chains, because we're utilizing native best practices, the migration between major versions there are going to be fairly simple. You just go and open up your native Ides, perform the updates that are needed, and you're good. So all that together, let's actually switch over to our code editor and actually look at an app. So I have a small little Angular app here, nothing too drastic. It is using standalone components. So don't worry if you don't know what standalone components are or how to use them yet. You'll find out all about [email protected] and some upcoming versions of Angular. Essentially it's a module list approach to using Angular. So I'm just going to run my web server, let this get up and running, and then I will open it up here in my browser. And 4200 you can see we're just using a blank angular app. There's nothing fancy here, there's no UI library. I would assume that most folks have a UI library of choice. Obviously, I think Ionic is a really great UI library, but there's also Angular material tailwind. If you want to run your own custom one or probably use something different in your own custom solution, what's the other one? Tia or your own? For another UI library of choice, you can check that out. Whatever UI library you're using, it doesn't really matter. You should just be using one. And here inside of our app, we just have whatever Angular provides as the standard widget of choice. So we're not going to focus too much on building out UI and having these features. What we are going to focus on is how to actually call native features and then deploy this app to a mobile device. So I had mentioned it earlier during the slides, and we're going to incorporate Geolocation. I think Geolocation is a great example here because it touches on several features that are unique to the native platforms that don't exist inside of the web. So we're going to install at Capacitor and we're going to install the Geolocation plugin. Getting ahead of myself, but before we do that, we need to install Capacitor itself into the project. So Capacitor exists as two parts. It exists as a core library that we have and then this very slim CLI that we can incorporate for performing runs and builds of our app. So we're going to install these real quick. Let NPM do its thing, and if I spell Capacitor correct, let's install Corford and then we'll install CLI. All right, so that is available. Now, with those packages installed, we can then run this Capacitor command, which will init a new project. We'll run MPX Cap in it. Now, Cap is just a shorthand. As you can see, spelling Capacitor can be a challenge even for me as a person who has to write the name every single day. So the shorthand is very welcome. And then we get presented with this prompt, which essentially is going to walk us through the setup process. So we get asked to pick a name for our app which will be displayed to the users. In this case, I'm just going to stick with what the default is, which it pulls from your package JSON. So we're going to say Ng Webinar is the name, and then we're going to pick the package ID. Now, package ID is essentially just a way for our apps to have a unique ID in the app store. In this case, we're going to keep example app, but if you're building software company, it's normally a reverse domain. For Ionic, it's more or less going to be IO, Ionic, whatever. So keep that in mind when you go ahead and create this stuff. Now, from here, once this is done, we get a config file created for us, and then we get presented with this where to go next for our link to the docs. We're not going to use that because we don't need that. You have me and then we're going to install our Geolocation plugin. Now the Geolocation plugin is split out into its own thing as well as all of the core APIs that Capacitor provides. So that way you do not get things included into your app that you aren't using. For instance, if you include the camera plug in but you don't ever call the camera, apple tends to look down on that and will say, hey, you're not going to use a camera, don't include the code for it. So things you keep in mind, we have a very fine grain control over what features get added. Now we're going to close that and have our app still running. And we'll just resize the window and we're going to come over to our main app component. Now inside of this app component, we're going to go ahead as soon as I finish that editor settings. As soon as we're in here, we're going to create this on init callback now on it is just going to fire whenever the app component has been created. And we're going to use this to create our first little bit of native code. So let's go ahead and import at the top of our project from Capacitor Geolocation, we're going to import the Geolocation class. Now this class is going to go ahead and just give us access to all of the Geolocation APIs and inside of our net we'll just say Geolocation request permission. So, fairly simple, this will go ahead and prompt the users like, hey, can we get location data, let's save. And then we're going to open up our browser and just make sure that this is all good. Just to be sure, I'm going to restart my server because sometimes the dev server doesn't pick up when you've installed new packages in the background. So let's do some quick window management. Bring this down here and here we go. And we can also check the it is a promise. So what we're doing is getting stuck inside of the promise, not getting resolved. Let's wait this so this is still not firing and that's for a very good reason. Geolocation permissions on the browser are not really, they're not that great. Your browser has to get location data basically or get permission to do this as soon as you call that data. So let's go ahead and add that. So we'll create a new method called get location and it's going to be an async method because every method inside a Capacitor is asynchronous and we're going to say const. And I know this is going to get distracted later on where we're going to say there's going to be a chords variable later on and we'll say await Geolocation get current position. We can simply do that and everything should be available. Check out what we have here. So this coordinate variable that we have is going to be an object and we're going to get things like the latitude, longitude accuracy and then we get a few other pieces of information. Here we have altitude accuracy which could be a number, could be null, could be undefined, altitude, speed, heading, all these could be null or just not provided. This is because each platform has their own quirks with what kind of data they provide. So I could be in the web and I'm not going to get the heading, the speed, the altitude because the location data just does not provide that. But I could be on iOS or I could be on Android and I can get all that data. So this way we can safely access features as they are provided and essentially enhance the app the more closer to native that we get. So with those features what we're going to do is we're going to set that onto a local variable here. So we'll say private actually no, we need to make this public. We will say location data and we'll set that to null. For now we'll just ignore it for now. We won't provide any type information except for any don't ever do this, do the right thing, provide type information back inside of our get location method. Once we have all this we could say this location data is going to be an object. We're going to have a longitude and that is going to be set to cords longitude when your editor doesn't mess up typing for you. And then we'll also have latitude which is going to be chord latitude. Now all that together is going to work for us. Now inside of our app component let's get rid of keep the content but we're going to get rid of most of this stuff, specifically the cards. And we're going to create a pre tag and then we will say location data and just pass that through some JSON pipes. And then we will go ahead and create our button and attach a click handler here. So the click handler is going to say get location, where in the world am I? And just to make sure that we are doing things correctly we're actually going to use a nice little feature that our browser has available. So the browser is going to let me set the location to be Mountain View and I could hard code that to be these values or it could be anything or I could even override that to say hey location data for some reason isn't available. So just making sure that I have that set up so that way I'm not getting at my real location. Let's go ahead, just scroll that down and then save this file. So where in the world am I? Okay now we get a nice little permission prompt over here. Localhost 4200 wants to know your location. We will allow it and then we will go ahead and try to get that again. Some reason the data has been returned. So this is already getting the location data under the hood. What we're actually doing is running Navigator get currentlocation or Navigator Geolocation, not get currentlocation. So if we're using this and this is something that is built into the browser, why are we providing a plug in or an API? Can't we just use whatever Geolocation provides? No. Because of these permission models, we need to have a per platform implementation. It becomes a lot more clear when we think about when we think about the native projects. So let's go ahead and initialize these native projects. I'm going to set this up. What we'll do is we will run NPM install at Capacitor and then I'm going to install iOS. I've tried to do Android Live and Android Studio tends to take forever. Tap add iOS. Once our project has been created, we're going to go ahead, set the MPX, tap add command, which is going to go ahead and maintain all of the project creation for us. So it'll go ahead, you'll see, we got a warning. It couldn't run the Sync command, meaning that we haven't built our web project yet, but it'll add the iOS platform and give us a link to some docs for what our workflow should be like. So let's do a quick little build here. It will go ahead and run our build. And you can see I'm using Es build here because I'm one for trying things that are experimental. And then we'll come back up to our editor and we're going to quickly configure things to work correctly and that we're pulling the right source code. So for instance, if you are setting up a project inside, say Amano repo, you could have multiple things getting built to disk, but you're only ever including one project into the need of the configuration. This is just something that you're going to want to make sure you have set up correctly. I didn't do it manually, so I'm just editing this now. Once that is done, you can see we have this iOS folder created and it's creating the workspace, the app for us create the Pod file, which is iOS version of essentially a package JSON. Nothing really too drastic. Let's go ahead and we can actually quit out of the editor once we have that done. Let's run NPX tap sync we're going to sync the iOS project now. Sync will go ahead and copy all of our web assets. But then it's running this Pod install command now because this is using Pod install, it's fetching all the native dependencies needed for our iOS project and it takes a few seconds. And then we can run NPX Cap, open iOS. This will go ahead and open up the iOS workspace for us. It'll be fairly quick. And then we're going to go ahead and just tweak a few different settings because of how iOS works, we need to be explicit about what kind of features we're requesting from our app. So we're going to come to this little file tree. We'll say, go to the app, open up this info plist, and we're going to add a new row. And then we're going to say location when in use. Is that going to give me what I need? And it won't give me what I need? I think maybe. Come on. All right. So it's not giving me the location stuff that I need, potentially. Well, it's in the privacy. So here we go. So you can see iOS has a lot of permissions, which is great, but they can be a little confusing. So we're going to pick the location always and when in use feature. And this is essentially going to tell the user, hey, we want to get your location. And then we have to provide a value for telling the user why we need this location. I would like to know where you are. We're going to try to be pretty explicit, provide a good message. If you're doing this yourself, be very clear. You probably have seen apps that request these permissions and have either provided good messages or bad messages. You would probably want to provide a good message. I'm not going to assume that you would want to provide a bad message because I don't know you. With that in place, we can then go ahead and run our app and all that's going to be is hitting this little Play button. Now, the design has changed a little bit, but I used to say that Xcode is essentially itunes, but for iOS developers. So this is not that confusing of an app. It can be a little cumbersome, but pretty simple to see. Okay, here's the app. Here the targets that I could deploy to Play is going to be my build, and we're going to let that run real quick to see if we have our simulator up and running. So I'm going to give it a second to go ahead and boot up. If you've never done any iOS development before, iPhone is notorious for being fairly slow. And you can see we have a warning here. So typically when this app starts up, we would have gotten a permission dialogue to say, hey, can we know where your location is? But we didn't, and Capacitor will be smart enough to know why. So we can say, Geolocation request permission. This app has attempted to access privacy sensitive data. What do we do? We just have to provide this new key. So let's go back over to our info pls. We're going to add another row. We'll just paste that in there and just say, I would really like to know where you are. And then we can do a quick little build. Again, allow Ng webinar to use your location. We can provide precise allow once we're going to. Allow it once and let that basically provide the course. Location granted and then location data granted. So this will be our actual return value from request. Once we're in here, let's go ahead and click the buttons and you can see up in the top we get the little location indicator saying that we are grabbing your location and then we get the actual data back from our call. So all this is working really well. Now why are we using a plug in in this case when we could be using Navigator Geolocation? This is technically a web view right here. Like if we open up our dev tools, we can see that this app is able to inspect everything going on here. So we can see we got the body, the app room, all of our components. Why are we still using a plugin? Well, because if we were to try to call this from this setup right inside of our JavaScript code, we actually get double prompted. We'll get a prompt from the JavaScript using Navigator Geolocation saying hey, index HTML would like to get your location. And then we'll get another prompt from the app saying, hey, this app would like to get your location. So we get a double prompt, not necessarily the best experience. And then we also miss out on all of that location data. So let's actually look at our app component again and instead of just picking out all of the data that we have here, let's just spread out everything inside of coordinates and see what we get between the two platforms. So I'm going to do a quick little build. Again, should only take a few seconds this time. Thank you Angular and your caching mechanism and then NPX cap sync iOS. And then we will run inside of our app, let this do its thing and then instead I'm just going to run start in this browser and let this kick back up again. So again we get our prompt allow once and then said let's get all that location data and then we'll just do some quick little window management. You can see our location should be prompted. If we would actually go ahead and get this up and running, that'd be great. What is the error here? Is there an error default not implemented on the web? Okay, that is the other location data. I don't know why it's not showing up here, HTML, but you can see inside of iOS. We are getting all of our data that we would want to get and could build out a pretty great UI here. So we could be building something like a location tracking for maybe if you have children that you would like to know where they are based on phone to something like a delivery service where you want to tell the users hey, your driver is here, here's your location. And you could build out the mapping features for this as well. So all that location data is being returned and is a fine, detailed location. What's probably more interesting in this regard is how we could do this and then have access to things like tracking location. It's something that people have always wanted to do for some reason. So let's say async Track Location, and we're going to call Track Location and we're going to also create this private location tracker. Now, location tracker is going to be a string and we are going to say this location tracker is going to equal Geolocation watch position. Now, it returns a bunch of different stuff. We have a set of options that we could pass if you wanted to I'm passing empty object. And then we get a callback so we could get the location. We'll say location data and then we could get actually, now let's go ahead and just say cords, because I know it's going to be there. And then if we have an error, we'll handle that however we want. Then inside of that callback, we'll just say rent and repeat. This location is going to be the coordinates. And then this location tracker this location tracker needs to be cleaned up because it'll run indefinitely. So in RNG on destroy, we'll just say this async I believe we'll say geolocation. If I can spell it right, geolocation clearwatch. And we're going to give it the ID of this location tracker. So here's how the whole flow works just to be sure. We're going to call track location. That is going to kick off a native location service, which will watch the position and return that data whenever we get new data. But that watch is going to return a new ID for the watcher itself. Now, when our component gets destroyed, we're going to want to clear that watch. Otherwise we would just be getting data from the native location service even if we don't need it. So in a more complex app, we're probably not going to have something as simple as this, but we could be embedding this in, say, a native app or an app instance where we're changing views. We're not going to want to have that running in the background when we go from slash maps to about or slashorder. So we need to have some way to control that and pause it or stop it whenever it's in the background. So with this set up, let's go ahead and try to figure out how to get this on our computer. Let's figure out why this is also promise. Right, there we go. Add under. Fine. Thank you TypeScript and your auto completion for telling me how to solve this. What's going on here? I will tell you that that is going to exist. Actually. We'll be smart. We won't try to be clever. We'll just say lock and lock cords. I can guarantee you those coordinates are going to be there because I'm smart. Actually, I don't need it to be a promise of a string. We just need it to be a string. I will unfurl the promise afterwards. Okay, everything is good. Now we're going to go ahead and we're going to try this actually we forgot to instead of get location, we'll call track location. So let's go ahead and get this running. Now we could go ahead and try to run this on the device and do a constant build, but that's kind of boring. Let's go ahead and actually try to get this up and running using library load. So I have this going with Localhost 42 and if I recall, we can set this inside of our capacitor config. Now this has a feature where we can say the server provides us or the well, actually see what we need. Did they get rid of it? Okay, so it might have got been removed. So we're going to actually skip that altogether. Apologies, I was mistaken. So instead of doing the serve, we're just going to do our build again and we're going to sync this over. There has been a feature, I could be mistaken, where you could deploy it to your iOS device and have it do a live reload. Instead we're just going to do a sync and we're going to let this location data get moved over to iOS. So sync has succeeded. Let's go over to our app and we're going to start up our app again. Great. We'll get our prompt allow once location granted and then let's go ahead and track the location. You can see we're already getting logs printed to our app. So this is already going really well. Now what we can do even better is inside of the app we could say our location is going to be constant and let's just delete all the login information. That way we're not spamming it. But you can see that location isn't changing. We're staying at the same place constantly. If we were to go ahead and open up our simulator, we can actually change that to be a freeway drive. So location tracking as people are on the move or inside of your app or any app is moving, this can all be mapped back to say something like Google Maps or open layers and you could build out the mapping features with a fairly few lines of code, which is really great. So we are coming up to that time and I want to leave some time for questions. So I'll wrap up here and kind of go over what we talked about. So first off, if we want to add this to an existing project, first I would suggest try this out, create a new git repository, create a new branch and install the core package and then install the core CLI and run cap in it. We'll go ahead it'll enhance your web app. Even if you're not using native features or planning to deploy to native, this could still be beneficial to you. If you're curious about trying other features or learning more about what Capacitor can do, you can go to capacitor It'll show you how to get started, what product structure should look like, how the workflow should behave, and then our Docs, which will give you more in depth guide about how to work with the APIs, how to call different plugins, what's available for the Core API, et cetera. If you want to try some other features that maybe weren't suited for Core but are definitely great features, there is a Capacitor community where they have extended the plugin ecosystem to include things like stripe payments, firebase cloud messaging, Facebook login and authentication, SQL light databases, even a lot of great things in there. Pretty happy that we have a and know that this is something that's being used not just by hackers and indie startups. There's a lot of great logos that we can throw out here, but I think some really cool ones are the Blue Cross and Blue Shield. BBC are all using capacitor. We've gotten their permission to use this. But you're in good company. This stuff isn't going away, and it's being used by large enterprises as a great way to build their app. So try it out. These folks have and they're pretty happy. You could be happy too. Just quick little parting thoughts. Cross platform here. In this case, we're just reducing the amount of code that we have to write to create a location tracker. We had to create maybe five lines of code. Fantastic. I don't have to maintain the location services in the background. I know what I need to maintain. If I want to have full at native access to, say, our Swift code or to our Java code, I can do that too. I opened up Xcode and I had access to modify our location data or our Info plist by just opening it. It's not a scary, scary thing. The native projects are pretty simple to deal with these days. The web app is just the part that we want to write it. So thank you so much. I love to go to Questions now. If you have any again, you can find me on Twitter, M Harington. And if you're going to be at ng. Comp, I look forward to seeing you. It's going to be a great time. All right, we have some questions coming in here and he wants to know, is this web storm or a cool theme on Vs code? This is actually vim because I am an uber nerd. But if you would like to code the way that my codes. I have a scene on Vs code called oceanic. Next look for the one written by Mike Hardington. It is the same car being just ported over. An anonymous attendee would like to know that they develop on a Windows box. Would it be possible to get back here? Would it be possible to do this, or would you need a Mac to build for the iOS version? So, short answer is that you would probably need a Mac at some point. But if you are a Windows developer, we have a solution out there. It's a paint solution, so take that for what it's worth, but it allows you to do the remote builds for iOS without ever having to use a Mac. So it could be something worth checking out. Again, it's a paid additional service. It's not free. There are open source alternatives that you could use but take out how you will. We're using Iatn for localization what should be the web there in capacitor config in this case as there will be multiple sources. Okay, great question. So if you're building an app with localized data, which really great on you, we actually have another project called Trapeze, which haven't fully announced it yet, but it is essentially a way for you to configure your project for a different platform for different IAT and build. So if you're doing something for appean for the English version, and then you have Spanish version and a Portuguese version, what have you, you can go ahead and you can figure all that here inside of using this tool called Trapeze. And don't go check it out right now. Know that it is possible because we're still building out this. You're getting an early look at it, but soon, I promise it'll be available. Victor is asking, is capacitor the new Ionic? Capacitor has been created by one of the best way to think of it is that Capacitor is our solution to the cross platform runtime. Ionic is still viable for the UI layer. We swapped out what was cordova for Capacitor at this point. So it's not the new Ionic, but it is the new engine that Ionic uses. Victor, can I watch a recording from the beginning? Yes. The recording will be made available afterwards. Victor so you'll be able to catch the very beginning and then addie. If you're using Capacitor for PWA, we probably still create a different layer for native. Great question. If you're only doing a progressive web app and you're not intending to deploy to the iOS or Android App Store, you can simply just run your build as you would normally be doing and then deploy that disk target. The capacitor code that you will be including is nothing more than actually, let's take a look at it. The capacitor code that will be included in there is fairly simple. It's just going to include the Geolocation API in this case for our app. So it's not going to be bloating your project. For some of the APIs, we have things like Camera, which have their own web implementation, so you could be doing stuff like that. But if you're just targeting PWA, you wouldn't create a native project like iOS or Android project. You'd still just be deploying what is used in your disk target. And I think that's all the questions. Looks like it. So thank you all so much for joining. This has been a lot of fun. Hopefully I'll be able to see you all at Ngcop. If you are intending. If not, feel free to reach out to me again. M Hardington on Twitter. Have a great day. Bye.