When building an app, there are many options choices developers need to make. Is it a web app? Does need to be a native app? What should I use for UI? In this workshop will look at how to make use of Ionic for building your app and how to deploy it to not only the web, but native as well.
Building for Web and Native with Ionic & React
When building an app, there are many options choices developers need to make. Is it a web app? Does need to be a native app? What should I use for UI? In this workshop will look at how to make use of Ionic for building your app and how to deploy it to not only the web, but native as well.
AI Generated Video Summary
This workshop covers building for web and native with Ionic and React, including integration, project setup, and app structure. It explores rendering components, positioning with slots, and adding action and translucent properties. The session also covers location tracking with Capacitor and geolocation, exploring native capabilities, and launching the app in the iOS simulator. It discusses real-time updates and state management, implementing a track location feature, and syncing with Android. The workshop concludes with insights on Ionic as a web view component, plugins for native functionality, and available resources.
1. Introduction to Ionic and React
Let's get started. So, yeah, this is a little webinar session. Building for web and native with Ionian and React. We're going to try to go through a bunch of different things. We're going to cover a lot of the aspects of Ionic and React. How to work with core framework itself. Then how to sprinkle in some native interactions with another project called Capacitor that we also build. And how you can take all of those pieces together make a really nice native app using just web technologies and no native technologies at all.
So again, quick little housekeeping note. This is being recorded. All of it will be available afterwards. And if you have any questions, please use the Q&A feature, throw in some questions, try to go through them as we get them. And if there's anything towards the end that you aren't sure of, ask it then. We'll save about five minutes for questions, maybe a little bit more depending on the amount that we have, but we'll try to still continue to wrap up on time. So dive into it and get started. Hello, slides work.
Common components that you should expect to see are things like cards, alert controls, toggles, or switches, range components, button icons, segmented controls, your kind of standard native-like component design. So everything from full navigation components and TAB-based interfaces is all possible and all within the framework. Some of these components, too, like, for instance, we have a component called modal, have a built-in animation and gesture support. So that way, if you were to open up a modal and you're on a device that allows you to swipe to dismiss it, that gesture should automatically be registered inside of that component. So we provide all of that in there, already pre-configured, and you can tweak it as you need. And the last little bit, which I think is really interesting, is something like a CSS Utilities file. So we ship with a bunch of utilities. You can kind of think of it like tailwind light. You don't need an extra build system. You just get all these classes. And if you don't need them, you can just comment out the file, and it removes it from the final output. So let's take a look at some of these components, and it's like a real quick example. We have this card component, which I think is a really great middle ground, and kind of demonstrates some of the design differences. It also demonstrates something that I like to point out, of like, this atomic design principle, where the card subtitle, card title, the text, all these buttons inside of this card right here, are actually subcomponents that can be composed together inside of this one greater card to create something that's very tailored and perfectly sized. The padding and margin around all the buttons are perfectly adjusted for this one example. But the card itself also provides the context of knowing what platform it's on. So for instance, this is an iOS, we have a very iOS looking design feel. We have this nice little box shadow around the card itself. The markup for this is a little bit truncated just to account for spacing and size, but we have this card this image and then the card content.
2. Ionic and React Integration
The markup and design principles differ when switching to material design mode. Ionic is framework agnostic, supporting Angular, React, Vue, or no framework at all. Standard components are shipped as dedicated bindings for each framework. Router integration includes pre-configured animations and transitions, as well as stack navigation for multiple nested routes. Ionic has a large developer community and a developer forum for support. The framework is MIT open source and has future releases planned. TypeScript is used for consistency and better developer experience. The focus is on building UI and integrating with native features. To start a project, the Ionic CLI is installed and used to create a new project, with options for different starting templates.
And below it in the actual HTML there is a button and some icons as well as the subtitle and title elements. As we jump over to material, or this material design mode or Android mode, however you want to register it in your mind, we have something completely different. So the markup stays the same, but we have a much, I would say, less intense drop shadow or box shadow where the shadow itself just seems like it's a little bit of paper above the surface, mimicking that material design principle really well.
The title and subtitle are a little bit further apart and actually different font sizes, so kind of toggling between the two, you can notice that the difference is more than just... Going too far ahead. You notice that the difference is pretty significant, enough to make it feel right at home for those platforms. Kind of going forward, the core framework itself is Framework Agnostic, so if you end up using Ionic and fall in love with it and then, for whatever reason, you change jobs and you're no longer using React, but you still want to use Ionic, don't worry. We support Angular React, Vue, or no framework at all, if that's something you would like to do.
What's great about that is that instead of you just kind of getting the components and you're left to figure everything else out, we ship those standard components as dedicated bindings for each framework. So, when you get a button, it's a full React button, provides all of the standard kind of implementations that you would see a regular React component, it just happens to also render out a framework agnostic component. The one thing that I think is really interesting is the router integration. So, we integrate with React Router to provide the pre-configured animations and transitions, but we also do something that's called stack navigation. This is something you see native all the time where you could have multiple router views or multiple outlets for your routers, for your routes, and then each one of them is able to maintain a separate navigation stack. So, if you think of any tab-based interface, you could have multiple nested routes all being maintained alongside one another.
For anyone who does end up using Ionic or is in a company that is thinking about it, don't worry, you probably will be able to find somebody all over the world. We have over 5 million developers, there's over 10 million apps being created. There's this really nice site out there called App Figures that shows Ionic as one of the top mobile SDKs for native development, which is really great. So, chances are, you're gonna be able to find people out there who know the technology and are able to build great apps with it. And if you do end up having a question or want to post something you built or actually post a job posting, we have a developer forum that you can post that on and get all the help and activity, all the help for any thing that you're doing. And obviously, everything's all MIT open source, so you can find all of our GitHub activity online, check out what it is that we're building next and see what our plans are for future releases.
So, this is based on React. We're going to look at some of how the framework integrates with a React app. I don't feel like I need to sing the praises for React. Everyone kind of knows it, especially here, just some priming right now. We are going to be looking at this with TypeScript. So, I'm going to try to keep that there to a minimal. We ship with TypeScript out of the box for consistency, giving people probably the best developer experience that they could get, and also reducing potential for runtime errors because no one likes those, and we sure do not. So, might as well just make everything all TypeScript-based. I'm going to try to keep this from changing context too much. I'm going to focus on just the really basic pieces of the component. So I'm not gonna be integrating with various libraries, not gonna be using something like GraphQL, I'm just gonna focus on building out some UI and showing how that can work and how that can work with the native features that we'll add later. So to get started, we're going to switch over to my terminal and we're going to start a project. So here inside of my terminal, let me just bump up the font size real quick, we have a directory with a bunch of other projects, but we need to create a new one for React. So obviously we have no install, then we have npm, so those things are pretty much guaranteed and are required for most web apps these days. But with that installed, I can run npm install-g on a Ionic CLI, and that's going to install the CLI for Ionic itself. Now, the CLI that we have, it gives you a few core commands that you need to know, and gives you a start command, a build, and then a serve command, as kind of the core ones that you should be aware of. These all are how we can start a project, obviously, serve and then eventually build it. They actually act as wrappers around existing tools. So what I wanted, so if we were to say, Ionic start my react app, we get this little start command, which gives us a picker for our framework option. Like I said, we support all these other frameworks as well. We're gonna focus on react, and if you want to skip this at any point, you could just do dash dash type equals react. And that will effectively just pick that for you. So we have a few different starting templates or startup examples that you can use if that is something that you wanted. For example, you could have a blank app, which gives you essentially a single route and your left to figure out the rest on your own. You have a list starting project, which can be really useful if that is the kind of UI and you want to see the possibilities that we can get with lists. We have our My First app or a guided tutorial that we actually have on our website. Side menu, standard kind of Swipe to Reveal the Menu, tabs, think Twitter. And then this kind of Kitchen Sink Application which shows every component and ways that you can use it. We're going to start with the blank because it gives us the best base to show everything out. So while that is up and running, it's going to create our project behind the scenes.
3. Project Setup and App Structure
The project is created with preconfigured files and dependencies, including a source directory, public directory, config files for Ionic CLI, Capacitor for native deployment, and TypeScript config. The main app file is app.tsx, which imports components from react-router-dom and ionic-react. IonApp provides scoped styles and resets, while IonRouterOutlet manages route rendering. The Ion ReactRouter component is also used.
It's going to install some core dependencies. We should only take a moment. So while we're waiting for this, I know this is a remote event or remote session. So I'd love to know where everyone's tuning in from. Right now, I'm in London. So getting a little, little bit of that London or that English overcast, getting some clouds, skies and a little bit of rain. So, where's everyone else at? Nice, we have another person here in London. We have, let's see, Charlotte, North Carolina. We have Ireland, so not much different. Germany, Paris, Edinburgh, Scotland, Isle of Man, Brazil, Greece, Serbia, Poland, Israel, Denmark. Wow, we have a lot of people all over. Czech Republic, India, it's raining. Belarus. All lovely places that I would love to visit eventually once things kind of get a little bit nicer all around the world. But awesome, glad to see so many people from all around the world. Thank you all for joining in.
All right, so we have our project created. And we can just cd into it by saying my cd into, what did I call it? My React app. And you could use various editors with this. Don't do what I'm about to do. I use vim for my editor, so if you are curious about that, there's a whole bunch of resources out there. Use VS Code though. It's probably going to be better experience for you. I am just, I'm just a person that got the vim bug and was never able to get around it. So, here we come, we have a project which has a bunch of stuff kind of preconfigured. For example, we have a source component, our source directory, this public directory, a bunch of different config files for working with the Ionic CLI and potentially any Ionic services that we want to use afterwards, a capacitor for the eventual deployment to native, obviously our dependencies and then TypeScript config, and then public for everything else. So, we ship with manifest by default, index HTML. Basically, what we are given is a create react app project template that has all of the dependencies listed out for everything. So, as we get along in here, we obviously have the index.psx. So, this is using TypeScript, JSX. So, we're able to do all of our JSX and know that it's going to be type safe. And we'll get all of the same things like hover windows, error warnings when things don't actually... when things are actually going wrong. So, that way we can be a little bit smarter about our code. And then, obviously, we have the service worker stuff. And then, some web vitals as well. So, the main portion of our app, let's just keep it to this one file at the moment, is this app.tsx. Now, if you notice, automatically, we have a few different imports in here. So, we're importing things from react-router-dom. So, we are using the dom version of the router. So, we get our redirects, our routes, we have the ion-app and ion-router-outlet components from ionic-react. And then, this ionic-react-router component from this react-router package. So, let's kind of just do a quick little rearrangement to better explain things. So, what we have is this, these two packages, we have the core component that we're going to need for the app component. An app, and then, a router outlet. Basically, app, IonApp is a, kind of global-ish or a scoped way of saying any styles that get applied here, they're only going to be scoped to the, IonApp component. So, everything's gonna be scoped to this small context versus having globals leak out everywhere, and it's also gonna do some resets and normalization of other browser styles. The IonRouterOutlet component, gives, gives us the basis for where routes should render. So, we'll be able to have all that stack navigation, all manage through that. Obviously, the redirect and routes are very specific to React Router, but this Ion ReactRouter component seems a little sus.
4. React Router and Styling
React Router provides their own router component, but we provide the same component wrapped up to work with our own history. This separate package gives you the benefits of the router package plus animations. The core CSS, normalized structure, typography, and Tailwind-like classes are provided. The variables file handles global theming. The app component uses ion-app, React router, and router outlet to render and transition between components. CSS custom properties and variables are used for styling, with different styles applied based on the mode (e.g., dark mode, iOS, material design).
So, we can think of this as having this be our router component. So, React Router provides their own router, or their own router component, but it only behaves in a very particular way. And instead of trying to hack it together and make it all work, we actually provide that same component just wrapped up to work with our own history stuff. So, this is a separate package. You don't need to use it if that is something that you want to do, but you could actually, but this gives you the same benefits of that router package plus animations, which I'm always for animations.
Our main home component that we are trying to render, and then all of this different CSS. We could really replace this with like, we'll just say, import, Ionic, React, CSS. And we have Ionic.bundle.CSS to bundle everything together. But this gives us kind of the core stuff that we need. So, we have the core CSS, normalized structure and typography. And then the Tailwind-like classes that we can provide. So, how do I manage padding? We can give you all the classes that you need for that. Handling things with floating elements, text alignment, text transforms. Probably the most useful one that I love to mess with is this Flex Details, because I can't remember all of the Flexbox alignments and all their valid properties. This just does it for me. And then some display utils that you can use for hiding and showing various things when we get to different media queries. This one snuck in because of auto import. And then we have this variables file, which is our global theming. So, it's going to theme everything for us and make sure that our styles are applied throughout the app. Let's see what else I don't need there.
And then our app component itself is just using that ion-app, our React router, so our router component, and then this router outlet is where things will actually get rendered and we will transition between different components. So right now we have a route for our slash home and then a route for basically our index which is just going to redirect to home. So let's open this up, real quick save just to be sure, npm run start. So this would go ahead and run the React scripts in their dev server but we're actually just going to run ionic serve instead which in theory will do the same thing but it's going to provide some additional settings and options. So we're automatically going to change the port in the port to 8100 just happens to be our URL or our port. And it's going to start things up in your preferred browser versus defaulting to Chrome because not everyone uses Chrome. I know kind of blasphemy but I don't use Chrome. So let's just do some window management real quick. Right now we're loading up in dark mode which is provided by that variables file. So if we take a look at what we have in it, we just have this CSS file. We have all of the root styles that are getting applied. So if you've never used CSS custom properties or CSS variables, they're pretty sweet. For instance, if you notice we have this blue color here that is actually being derived from this ion color primary. So if we were to change this to say something like 0072 or actually, no, we'll just do 007 cause that's pretty obvious. We save did I have them defined elsewhere? I think I do. Yeah, we'll just change this down here real quick. We'll just do blue or no, we'll go back to our 072 or 007, that's what it was. Notice that changes and it also is redefined here in the dark mode. So let's change these back and change that back and all the colors are back to originally however they define. So this is basically just saying, hey, HTML, you handle CSS actually scoping pretty well, better than most people give it credit for. So we can just use this root selector to say, here are some CSS variables for me. If they're defined anywhere else other than root it'll use that variable. If it is in root we'll just use a default. So here we see we already have the colors that are primary being redefined in dark mode. And then we have other variables that are being redefined when we are on a specific mode. So this is targeting iOS. And then this other style is targeting a material design mode. All they're really doing is just changing some colors to feel more at home to those native theming capabilities. So let's actually take a look at the home.tsx. So this is making use of, you know, a few core components.
5. Ionic Components and State Setup
This part covers the content, header, page, title, and toolbar components in Ionic. The page component is a flex box that automatically adjusts the sizes of its components. The header and content components have fixed and flexible sizes, respectively. The responsive design mode allows for a dynamic header that fades in and out as the user scrolls. The explorer container component is discussed, and the session transitions to other components, starting with setting up state and rendering the Ion list and Ion item components.
This content, header, page, title, and toolbar components are all things that you're going to see pretty regularly inside of Ionic. Its explorer container is just a custom react component. And then the home.css is some styles that we're importing.
So originally we have or starting off with everything, we have this page component. Now, if we would inspect the DOM for all this, this page component is essentially a giant flex box where we can give it the, where it'll automatically lay out everything and adjust the sizes of those components appropriately. So you notice that this header right here is a fixed size. And then this content is actually filling up the rest of the space. So if we were to say, I don't know, take this toolbar, duplicate it and save, the styles will automatically update to account for that without having to calculate some positioning. Sounds like, like that shouldn't be possible or that shouldn't be like that difficult but you'd be surprised to actually how complicated this was in the past. So delete that second toolbar.
We have another header down here, which is pretty interesting. This is something that we do to mimic the actual responsive or the actual large big titles that you see in iOS. So let's do something that we'll take a look at, let's see, enter responsive design mode and then I'm just going to save because I never saved that original one and we'll just do a quick little reload. So if you notice that we have this giant blank title right here, and then as we start to scroll, we can kind of see that it disappears into the original header or to that top header. That top header, the title is centered right in the middle of the screen or the toolbar. And then as we start to scroll back, we can start to fade it out and bring back the original title and keep everything feeling nice at home inside of iOS. So this is something that is really, really fun to work with and fun to play around with and really drives that experience home.
Explorer container component is just, you know, another react component being shown here. And in fact, let's delete that and delete that as well. So let's see, where are we at for time? We're 30 minutes in. So I think we've gotten kind of a basic understanding of how this all works. Let's dive into some of the other components that we could work with here. So I'm just going to first do some housekeeping. I'm going to set up some state and then set state, use state and it's just going to have a name or it's going to be an array that has name foo ID is one. And then towards this content area we're going to come right below this Ion header and we're going to say render this Ion list component and we'll import that and then further along we're going to render this Ion item component. So this Ion item component is essentially just your standard, oh wow, that looks terrible. Apologies, let me just fix this up real quick. Like I said, you're better off using VS code in this case. Not what I use. So this Ion item component is essentially going to act as our standard kind of list element. We can think of a UL and an LI in standard HTML. This is going to give us the same thing. Okay, one moment folks. Key Panelists. Should be good now. All right, so let's kind of move on. Like I said, we have this Ion item. It's just going to give us like a standard little list item. In fact, let's take a look at how that looks at the moment. So we'll just say, Hello item. We'll save, come back to our browser. And here, we just have the standard list item. Let's actually swap out and go to the light themes. That way things are a little bit clearer. We have the list item. We have some of the different lines and the borders being set on it. If we're to change this to a non-iOS device, those look completely different on a re-themed and sized for material design. Let's swap out this item. We're going to just say, state.map. Now, we're going to take all of the items and we're just going to return all of that.
6. Rendering Components and Positioning with Slots
We render out all the components using standard React. To control the layout, we wrap the items in an ion label. We can also include another component, like a date, and use slots to position it perfectly centered. This gives the app a native feel and fits in with iOS expectations.
What is this complaining about? And say, item.name. We're just gonna render out all of this. We will save. Hello food. Was that a subtle little, little slip there. I might be a little hungry, but we can do that later. So we're just rendering everything else out. This is all standard React stuff.
But what if I want to say, render out the item.id? Well, right now it's kind of right next to the item or to the text. It's all, and if we were to duplicate that multiple times, it's just gonna to keep repeating. There's no layout control with that item, by default. Everything is actually flex box align on purpose. So if we want to say, have a header for our item and then some sub sub notes. If you think of a text messaging app, we can wrap this in something called an ion label and spell label right, import it. And then just throw all of this inside of the ion label. Save. All right, it's still not going to work. Well, at the moment, I guess, what is going on with that? Well, when this does like to work, let's say if we wrap everything and say paragraph, and delete those, too. With all that, everything kind of scales up appropriately. Let's just delete that label for a second. Yeah, so because nothing was set in a block level wrapper, that was why that wasn't working. No need for key. You can add a key. It's probably best practice, and it's probably giving me a warning underneath, item dot IP, but in this example, it's not probably necessary since there's only one item being rendered, but yes, obviously include a key to make sure that you're doing everything as performant as possible. So let's wrap this with our ion label again and then we'll just reformat. So we now have this block level component. It's rendering out all of our header subtext.
But we also want to include another component, and I'm going to click on note to get some additional information for whatever reason. Let's just say date.now, we want to render this date. Excuse the unformatted date. We're just going to keep as is. But I want this to render to the side of the component, but how do I get it to render like perfectly centered? So let's look at this element itself. So I'm just going to open up my dev tools. I'm going to zoom in on them, just to make sure it's clear and easy to read. So we have this IonList and then this IonItem, and these are actually reaching into the core components from Ionic. We're no longer actually touching the React components. This is everything that Ionic provides. What we get with this though, is the ability to target these core components and these web components from React and make sure that everything plays well together, part of why we wrap things as vanilla React components. So inside of IonItem, we have this shadow content and then we have these two things called slots. These slots are allowing us to position elements inside of that specific location without having to know those specific locations or depend on DOM structure. So inside of here, if we were to say slot equals, let's just say start. We can come over here and notice that it's going to align specifically to the start, which is outside of the border over here and adjusting appropriately for the actual size of the content. If we were to change our date.now call to something like, well, just say 3.40 PM and save real quick, it'll automatically resize. So, this is really great. If we were to open this in, say, an iPhone, we can see how that looks. The slot and the item actually center everything that's in the note section or in this start section. And if we were to change the start value to say, and it's going to adjust it to be on the other side and feel much more like a messaging app or feel much more like a standard iOS control. So, this is your standard iOS messaging app. Feels really good, feels really nice and native to the platform and fits in with what iOS is expecting. So, quick little aside, if you noticed we did start and end to, actually it's the fine left and right.
7. Rendering Components and Positioning with Slots
In left-to-right mode, the end becomes left and the start becomes the right to comply with user preferences. The app supports left-to-right and right-to-left writing systems. Slots allow for flexible positioning of components. The ion-buttons and ion-button components are used to create a button with an icon. The ion-icon package provides a collection of open source SVG icons. The button has its own slot content, allowing control over the rendering of the icon. The IonButtonsComponent can be aligned to the end of the toolbar using the slot attribute.
This is because we are in left-to-right mode. If we were to actually go to our index.html and change, I believe, dir equals right-to-left, we should be able to support that and now our end is actually the left. So, end becomes left, start becomes the right so we can fully comply with what a left-to-right or right-to-left kind of user would want.
So, this all really great. We're able to make sure our app is properly internationalized. It feels good for left-to-right writing systems and right-to-left writing systems. Small little thing like that that is just a little, that is very good and nice to have. So, we're gonna delete those extra items in there for the ID just to have an illustrative purpose.
What's last little bit on the slot is what's great is that we could put this item or ion-note anywhere in here. And as long as the element that we already tiled up does not have that slot, it'll automatically stay in that same slot. I guess that won't work. Interesting, that had worked in previous release. So, it is context aware. You need to know where slots are existing. As we just saw, I think maybe ion-label has a slot, so it doesn't know. So, if a component has a slot context, you need to make sure that you're making that component that you want to place in there a direct child in it. IE, ion-note needs to direct child of ion-item and not ion-label in this case. But the item-note in the slot positioning could be anywhere within that ion-item. So, here it's before the ion-label and it still stays the same. So, really nice little control over how things get rendered.
In here, let's say we wanted to go ahead and render out a button that could add more items to our list here. So, we're going to actually come up to this first header and we're going to create that. So, we're going to bring in ion-buttons, the multiple buttons in here. And then we're going to bring in ion-button. And I'll just type it out because autocomplete was being weird. So, we have a singular button and then this ion-buttons component and a singular ion-button component. These are just again some flex containers to make sure that if we have multiple buttons they all align appropriately and are evenly spaced in a given context. We only need one. We're also going to import this, ion-icon component. And we're going to import that and then we're going to set the icon to a specific icon in here. So we're going to use this add icon and this add icon is going to be from a package we haven't imported yet or talked about, and it's from this ion-icon package. So this ion-icon package is our own collection, ionic.io slash ionicons. It's our own collection of open source icons. They're all just a collection of SVG icons that you can use in any project. We provide the SVG that you can just reference and you can use them as either a, let's see, an HTML tag in a non-framework situation, or you could use them like we're about to inside of a framework. So here we're going to bring in the add icon and we're going to set the icon to load up that SVG directly. This was asked to me recently. In here we noticed that we have one approach for loading up an icon, and this is using the icon's own built in loader. In this case, we're saying that there is going to be an icon named Airplane Outline, and we're asking the icon itself to load up that SVG, but because we're in React and we have build tools at our disposal, we can actually load that SVG up automatically by just passing it the SVG directly, so this gives us all of those icons that we want, and we can just directly import it, and the icon will automatically get, or the SVG will automatically get rendered, and also worth noting is that this button has its own slot content, and let's just save this real quick to see what I'm talking about. Actually have several slots that we're going to look at, so if we inspect, we have this tool bar, which has its own slot for start, secondary, primary, and then end, and then we have this button, which also provides its own slot for choosing where the icon should render. For instance, if we were to say, add item, we could basically control should that icon get rendered? See, in slot equals start. Should it get rendered at the start of it, at the end of it? Or should we get rid of the text, and just do icon only? So this would get changed, the actual hover effect in the button click. If we were to open in a material design mode, we get a proper ripple on that button, and it feels good. What about accessibility? Is it possible to add aria-label? For which button? While I wait for that, I'm going to finish up the last slot. If we were to, or what aria-label would you like to add for which component? So for this IonButtonsComponent, we notice that it's kind of janky right here. It's aligning below. It actually wants us to be on this end side over here. So IonButtons, we can say slot equals end. And now that this slot is going to place it all the way on the right side of the toolbar. So if we go over, we have our buttons working really well, it's properly placed.
8. Adding Action and Translucent Property
We add a click handler to set the state and update the rendering. The content automatically adjusts to the scroll container. On the iPhone, we can set the translucent property to true for a nice effect. The frosted glass effect feels right at home for iOS.
Let's add up a quick little action for this. We're just going to add a click handler and we're going to say, Add Item. It can be whatever we want. On click, and we'll say, const add item, just going to set state. And we're going to pass it in. Obviously the array, and we're going to spread over the original state. And then we're going to push in a new object where we'll just say, main equals, we'll just say bar, and then ID is just going to be state dot link plus one. So hopefully with all that in place, our state should automatically update. And so we have all of these things rendering out, and scroll a little bit, feels nice and good. And all of this is just automatically adjusting to that scroll container. If we switch over to the iPhone, we can add a little bit more. And this is something that I think is really fun, is if we were to actually come up to our header, we can set this translucent property to be true. Now translate, translucent. And if we were to reload, press this. I'm just gonna reload again, and start to scroll. You can kind of already see it as the title kinda passes through, we get to see some of the translucency, and I think it actually looks better in dark mode. We can kinda see it hovering over there. A nice example of this, and this is really just an aside, if we were to come up to this app that I've been working on for some time now. Again, mimic iPhone, let the browser reload. As we start to scroll, it works a lot better with images, but you can see that frosted glass effect that feels right at home for iOS. This is just a total aside.
9. Location Tracking with Capacitor and Geolocation
Continuing on, we render the items and explore the possibilities of using the capacitor package for location tracking. Capacitor is a cross-platform runtime solution that allows deploying web apps to native app stores while accessing native capabilities. It provides location services, API extensions, and the ability to write custom extensions. We import the geolocation package and set up the component to display longitude and latitude. With the geolocation component installed, we import the geolocation class and create a function to get the current position. We handle the button click event to retrieve the location and display the latitude and longitude. We also handle the limitations of getting location data and set up the state for latitude and longitude. We destructure the coordinates and update the state accordingly.
Okay, so continuing on, we have the items being rendered out. Looking pretty good, we have some nice rubber band effect, what else can we do here? Well, let's say we wanna do something different. We don't just want to have this item tracker. Say, we want to have a location tracker. We want to do something like track a location over a given time. So, what if we use something from another package called a capacitor? So, capacitor itself is a add-on that we've worked on and so that the docs real quick, it is our cross platform runtime solution. So you get your web app, you can wrap it up in the capacitor runtime. It's going to be, allow you to deploy to a native app store and still access all of the native capabilities that iOS and Android provide. So, it gives you all of these great location services, all these great API extensions like notifications location services, camera or the ability to write your own custom extensions via this native package. In this case, we're looking at Swift and we are importing the different packages that we would, implementing these different functions that we'd want to provide. So if we want to say, show a native alert controller we can do that, we present it or if we want to say, do something different it just be a matter of calling the right API. Capacitor itself is also framework agnostic. I say, we support all these other frameworks but we're going to look at one real quick for react and we're going to import this geolocation package. I'm a little biased because I wrote these docs but this is a great way to see the different location coordinates and render this out. So we're going to come over to our editor again and let's just stop the dev server from running and we're going to run npm install capacitor geolocation. So geolocation is pretty standard stuff. We're able to do this in obviously both in the browser already. So why would we need a plugin for this? Well, as we're going to see geolocation inside of a browser can be quite buggy but also geolocation on a native device requires a whole another different set of services to be used. So we're actually going to, we're going to remove some of this content or actually yeah, we'll keep this here and we'll just create some additional stuff. So if we had the art H1 and we're just gonna say geolocation and then we'll have a couple of paragraph tags. Longitude and we'll define that later. Let's see. Latitude, believe I spelt that right. And just to make sure, so I don't feel self-conscious about that, we're just going to short that to long and lat and then we're going to use this Ion Button component which gives us a really nice, component that feels at home for iOS and Android. So we're going to also use this expand property and set it to be a block level component and we're just going to say, Where am I? So this is just going to obviously get the location and we're going to render that out into these two paragraph tags. So with the component installed, that setup, let's import the, let's import a few things. We're first going to import from at capacitor geolocation and we're going to import the geolocation class and then inside of our component itself, we're going to create a new function, say get lock and that's just going to equal an arrow function where it's an async function and we're just say const lock is going to equal await geolocation, get current position. So at this moment, we'll just log that out and we'll just add that handler to our ion button. So we'll say on click and then get lock. So let that do it's thing. And at this point we're going to see a limitation. Oh, we could do this at localhost, couldn't do it before. We'll say, hey, would you like to get the current location? Would you like to allow that? Let's go ahead. And here we get some location data. So obviously we get the coordinates of where an individual could be. We have the timestamp and then we have all of these additional properties inside those coordinates. So the ones that we care about are obviously latitude and longitude, but there's also things like the accuracy, which can change depending on how you're getting location. Altitude, altitude accuracy, floor level, approximately heading and the general speed at which you're going. So we only care about the latitude. So we're going to say, give me the cords or give me GEO dot lat and then, or GEO dot long, and we're going to enter out GEO dot lat. And then we're going to create const GEO GEO and then set GEO. I'm going to create this real quick, and this is just going to use state and it's going to be lat, null, and long is also null. So we're just going to set those. Notice my little spell mistake. So with those coordinates, we could actually just care only about the coords itself. So we could destructure this and say, instead of just getting all locations, let's just get the coordinates. And then we could say set GEO and lat is going to equal to coordinates.latitude, and then longitude is going to be coords.longitude. And this is unfortunately just one of TypeScript little quirks is that it doesn't like it when you find something as a null value. So we're just going to say lat is going to equal a number or null and then long is also going to be a number or null just to have a little bit of type safety. And then we'll delete that console.log cause we don't really need that anymore.
10. Exploring Capacitor and Native Capabilities
We're going to explore how the capacitor side of things works, specifically for iOS. We'll install Capacitor iOS, which provides a starting template and utility functions.
So we're getting the location, we're gonna set it in here. We can save and then we can call get location and then automatically have that get rendered out. So this is fine, this is working. We are making calls to a location service. how does this work on say iOS? Well to do that, we're going to take a quick little look at how the capacitor side of things works. So this is going to touch on some of the native capabilities. And to do this, we're going to install Capacitor iOS. This is a separate little project package that provides the starting template as well as some utility functions.
11. Building and Launching the App in iOS Simulator
With Capacitor CLI installed, we add iOS to the project and perform a quick build. Accessibility is addressed by customizing the aria-label. Native dependencies like geolocation, haptics, and keyboards are installed. Xcode is launched to select iPhone models and modify app behavior. The location warning is added to the info.plist file. The app is built and launched in the iOS simulator.
With that installed we can call the Capacitor CLI directly. We can say npx cap add iOS. Could not find the build directory, something that you might see. Basically all that means is that you couldn't find our project or in our source code for that or our output code. So let's just do a quick little build. We're gonna let that do its thing. It's going to create an optimized production build and hopefully I'm gonna answer the question, just take a guess, about accessibility. Is it possible to add an aria-label? And if we were to actually look at this, you can pass all that stuff in. We do try to make sure that we give things a proper aria by default, but if you wanna customize that further, you could pass that in as well. We'll automatically just reflect that down.
So our build is there. Our native project has been, or our web project has been created for us. Let's go ahead and add that to, let's add that to the iOS project. So we'll say npx cap sync, and then sync it with the iOS project. That's gonna go ahead. It's going to install some native dependencies. We're installing dependencies for these packages. So it's gonna give us some utilities that we can access through the app itself, the geolocation service, haptics, keyboards, and then the status bar plugin. These are all kind of just default ones that we require inside of Ionic. So all those get provided out of the box. So let's go ahead, clear that screen. And then npx cap open iOS. Then we're going to see, yeah, it's gonna open up the right XCode version for me. Let's load up Xcode. If you've never used Xcode before, don't feel too intimidated. It still creeps me out every now and then. It's a very powerful tool. We're just gonna let it index real quick and we can select the different types of iPhones that we want to use. I'm just gonna use an iPhone 13. It's just standard run of the mill phone. You can see over here we have the app target and all of our different projects that we can work with. We have the CocoaPods and any other packages that we would want to use. Notice that the packages specific to Capacitor are being directed to use the node modules versions of those, so these are already being provided and we're just mapping those back. If you had someone on your team who wanted to include a custom CocoaPod, you could do so by just adding them to this target app and referencing that in your code. With this we have our app delegate, we're just touching on some of the native stuff. If you want to override some of the custom behaviors, you have full access to that, and then if you wanted to actually go ahead and modify this information, you can do so for that as well. And we actually do need to do that, and I'm going to cheat quickly because I never remember what the actual location warnings you need. So we need this NS location when in use, and we're going to add that to our info.plist. We're going to add a row, NS location when in use. Um, can we get your location please? And let's just, let's be, let's have some fun with this. So with that, we're just going to get the location when it's in use. If we were always wanting to grab this location, we can do that as well. Probably not something you would want to do, but for privacy reasons, but you can just grab it when the app is in use only. So we'll let this do its full native build and notice that we are doing a proper native build. Now this is generating a proper Xcode project so we need to run it through those tools. It's going to launch the app, which is going to launch this iOS simulator over here, which I don't know why that screen size is so huge but whatever we can deal with it. It does take a little bit to boot up because simulators. Yeah, I mean the iPhone Max Ultra Plus or whatever, some overly gaudy phone size. Alright, so we'll let this start up real quick. When it does boot up, we end up getting our app up and running and started.
12. Accessing Native Location Services
Let's click where am I and bypass the web view to directly access the native location services. We can get precise location services easily. However, there's a title discrepancy that requires a full rebuild. Let's make this simple change.
Let's get it going. Here we go, let's click where am I and you'll notice that we have a different prompt when we were inside the browser. We were getting the location prompt that is specific to the browser, but in this case, we're going to bypass the web view altogether and we're going to go directly to the native location services. Let's allow while using the app and we're going to print out the same location services. This time, we're actually getting really precise location services. So, if you're building an app that requires that precision, the native platform is going to be able to give you that and pretty easily, but I want to change this title. So right now, we're kind of in this fun little section where we have titles different. If I want to go through and rebuild this, I'd have, or fix that. I'd have to do a full rebuild. recompile. You're going to see some delay in just getting that offered just like this real simple change.
13. Starting the Library Load Server
We start up a library load server on the device using the ionic CLI. By passing the appropriate flags, we open up the server to reach different endpoints. This allows us to target specific devices and simulators. The process involves copying assets, syncing everything, refreshing the native project, and starting the dev server. It may take some time due to Xcode's build process.
So let's go ahead and actually start up a library load server on the device. So we're going to run ioniccap, run iOS, and we're going to use the ionic CLI to do this. And we're going to pass in a couple of flags. We'll say pass in dash dash library load and then dash dash external. This is just going to open up the library load server to be able to reach different end points. That way we're not locked down to local host. You can see we could target different devices, all of the actual simulators that are on the system. And what did I say, I ran a 13. We'll just target the iPhone 13 instead. It's going to copy all those assets, again, sync everything and do a full refresh of our native project. Go through and you start up our dev server and then it'll automatically let us prompt and automatically will prompt us to run on the emulator. So let us just kind of do its thing. This part does take a little bit because as you saw from building from Xcode, Native Builds inside of Xcode just happened to take a little bit. It was in 24 seconds. Not terrible, not also great, but it's just Xcode being Xcode, in my opinion.
14. Real-time Updates and State Management
We can resize and update the title of the app in real time. The location remains unchanged even after changing the titles. The app utilizes the fast refresh or hot reloading features from create react app, allowing for live updates and easy changes to the state and local components.
So here, we're on the device. Let's come over and resize real quick. We'll bring that right there and then go back to my editor. So I on title, let's select all of the blanks and then say react. We'll save, and then it's automatically updated. So if we want to even, we could get the location again and then we could change those titles back and notice that the location still stays. So we are using, it's using, what is it? Fast refresh or the hot reloading features from create react app. So as we're building this out, we can start to get some really nice live updates, add some more items, go back, actually change the title and keep it that way and know that all of the state and everything local to this component is going to stay right where we expect it.
15. Implementing Track Location Feature
Let's add a button and move it up to show a scrollable header. The app is working well. We can change the location on the iPhone simulator. Let's implement a track location feature that tracks the location as it changes over time. We use the geolocation.watchposition function to track the position and update the state accordingly. We also handle the cleanup by clearing the watch when the component is destroyed. Now, let's add a button for tracking the location.
In fact, let's go ahead and add this button and move it up further. Wanna show off a scrollable header. So we can start to see that the blur happens or the frosted glass effect comes in place. So our app is working pretty good.
In fact, if we were to come over here, this is just a nice little fun fact. If we come over to the iPhone, or the simulator features, we have these locations and we could change that location to be something different. So if we were to say, I wanna be at Apple park, you can get the location. It's gonna try to go out and grab those. Did that change? Let's go ahead and make sure that we are doing the right stuff. Features, we did change it. Let's go ahead and say, a city run. Well, there it goes, it updated. So these locations can be changed and we can start to do something I think, which is going to be real fun. And we have some time, so I wanna implement that. So let's say we want to have a track location feature. This is going to be a sink again, and it's just going to be a function that will track the location as it changes over time.
So we're going to first say, await const ID is going to equal await geolocation.watchposition. Now this watchposition gives us some options that we can pass, and then a callback to handle those position changes. So any options, we don't really need any, so we'll just pass an empty object. And then the callback is going to give us, I believe the callback signature is the... Let me just double check the docs for that. It's impossible to remember everything, so a good thing to know is where the docs are. The callback is actually a position, and then some errors. So let's just assume we're going to get all of that back. So we have the actual error position data that we have coming in, and let's just make sure that we are typing this correctly. Pose position, and then for null, and then down here, we'll just say set geo, we will say lat is going to equal position and we'll do some coordinates dot latitude, and then longitude is going to be position dot coordinates dot longitude. So we're just going to actually see what we got. The joys of TypeScript. Let's just go here and see if deleting all of this internally will fix that and it does. Now, let's double check what we are getting back from our watch position. We're returning back a string, which is actually the signature for our watcher. So basically, we are returning this whole, we are basically returning back this ID, which we can use to clear that out afterwards. So let's make some small changes above this. So we're going to say const, what do we want to call this tracker ID is going to be this ref and we'll set this to nothing for now. And then we'll say a trackerID.current is going to equal, we'll just say, come on TypeScript. We'll just set that up to work like that. So we'll just say trackerID at the moment is nothing. When we do get the tracker ID we will go ahead and we will reset the current ID to be the watch positions. So from here we do need to do some quick little cleanup. We can just say use effect or not use, yeah, use effect. I will get a little function in here. We'll pass in our empty array of dependencies since we don't really care and we'll just return a new function that says geolocation.clearWatch and the ID is trackerID.current. Okay. So, if you've never used that before, basically when this component gets destroyed, we're going to, before that happens, we're just going to clear that watch, so that way we're not ruining, we're not running memory usage. So let's go ahead and actually do this. So we have our button. We'll add a new one. Inside of this, we'll just say track me and then get lock. Instead of that we'll say track lock. Well just to make sure that we are doing well, what is this error? Okay.
16. Location Tracking and Debugging
We'll just make set this and apiece TypeScript momentarily. It could just be anything. Everyone should be happy. Let's bring up our simulator again and track our current location. This is a nice feature for delivery apps or any app that requires location tracking. There's a community plugin that extends the functionality. Debugging is possible using Safari's DevTools, which provide full-blown debugger capabilities. The same process can be done on Android as well.
We'll just make set this and apiece TypeScript momentarily. It could just be anything. And everyone should be happy. Everyone should be happy but me because I hate using anys.
So with that in place, let's bring up our simulator again. So first off, where are we? Well, that's our current location and let's go ahead and track. Now you might notice that this changes periodically. So this is again a real nice feature for any of the standard delivery apps or any app that require tracking the location. If for whatever reason, we were on the freeway and we want to track that, let's just go ahead and have that done. It's constantly updated. Now we notice that the interval that is being updated is a lot faster because we were tracking this. So right now, we're just constantly updating the location services.
And there's actually a community plugin that takes this a little bit further. And let's bring that up. Cause I do want to show that. I'm not going to install it. Capacitor community. It's this whole community organization that we've helped cultivate. We'll see background, location just lets you do some background locations that work well with iOS's own services. And then make sure that you can get the location while the app is running. It's very useful for tracking services.
Is this easy to debug? Very great question. Let's check out. I'll answer this. If this is easy to debug, let's go ahead and try to debug this. So I'm here inside of my iPhone or my iPhone simulator. Let's go ahead and try to debug this. So Safari actually has this really great debugging story where you could go ahead and just select the simulator running from, in the current app running. So because this is a debug build of your native app, you can debug this. We can go ahead, we can open up DevTools, and while they don't look exactly like Chrome's DevTools, they are pretty dang close. What we have is our elements tab where we can start to inspect everything inside of here. So let's go and inspect this item. We just click on it and we can start to inspect all this. Obviously, we have a console for everything that's being called, and you can see that we print out everything inside of the result as we get those results back from the native layer. We can even look at all of the sources and all of the scripts that we have. So full-blown debugger capabilities. Watching for network requests and even inspect the storage that we might possibly be setting here. The same thing would work on Android as well. In fact, let's try to do that. Let's try to run this on Android real quick. And this could potentially bite me. I have been fighting with Android as I... It's just Android. Let's go ahead and install this. Going to move my cameras over there. mpxcap.addandroid. Again, all we just did there was install the Android package which we did originally with iOS. This is just doing the same thing. So with this package installed, mpxcap.syncandroid. Let that kind of just do its thing.
17. Syncing with Android and Adding Permissions
We need to do a build to update and include the tracking stuff. Then we can sync with Android and open the Android project in Android Studio. We can check the progress by bringing up the build tab, which syncs the settings and packages. Once the sync is done, we can see the app and the libraries used. We need to add permissions for Android by placing them in the Manifests folder.
We're going to stop this process because it might be running pretty far in the background. Actually we need to do a build first to let that just update and include the tracking stuff. We'll do this with the command. Now we can sync with Android. If I actually type the command correctly From here, npm or npx cat open Android. We can open up the Android project inside of Android Studio. If you've never used Android Studio before It's pretty much your standard run-of-the-mill IntelliJ stuff. So you're going to get something that looks similar to WebStorm. Or PHPStorm if that's your thing. So with this running we can actually check out the progress of everything by bringing up this build tab. And all this does is go ahead and sync all of the different settings and different packages that are being used. Because we are using an Android project we are downloading different packages from Maven pulling this all in and installing it locally for our project. So in a moment when this is done running we should be able to see all of that here inside of our Explorer. So yeah, we have our app itself the different packages that are being used as libraries. Let's go ahead and double-check because I know I have some permissions that need to be added for Android. So let's just copy these down. And these can be placed inside of your, I believe it's in the res folder. Nope. And, Manifests. And all we're just going to do is add these to our permissions. Use permission and paste those in here.
18. Ionic as a Web View Component
Is Ionic mostly a web view component? It is a bunch of different things. We have the actual UI that we're rendering out. Everything inside of this app is all HTML. The app, once deployed to the real device, still uses HTML as the source. We create a native layer that renders the HTML and creates the Bridge layer. We can track native services using HTML and debug using Chrome DevTools. We can deploy the app as a Progressive Web App to platforms like Vercel, Netlify, GitHub Pages, or Firebase hosting. If there are any questions, feel free to ask. We handle missing web components using Capacitor PWA elements, which provides UI elements to fill the gap. You can conditionally handle situations based on the platform.
Is Ionic mostly a web view component? It is a bunch of different things. So we have the actual UI that we're rendering out. So, everything inside of this app is the... Let's let this run, we're going to see how this works with multiple services running. Basically everything that we have inside of this app is all HTML. The app, once it gets deployed to the real device, is still using HTML as the source for everything. What we end up doing is just creating this native layer, that renders all that HTML as HTML, and then creates the Bridge layer.
So everything here, where am I... It's still using the native capabilities for Android. Just this button happens to be built with HTML. So if we were to track location, we could track those services as well, and change how that is done by opening up, say, our Chrome DevTools. And let me just go ahead and minimize that. We could, say, go to Chrome, Inspect, to open up our DevTools. Here is our app itself. You can inspect this. Let's move this over. And here we still have all of the DevTools available to us. So we can start debugging these results as they come in. So, all really, really cool stuff, all just provided by the web, and we could also deploy this app to something like Vercel, Netlify, GitHub Pages, or Firebase hosting to get a Progressive Web App out of this.
We're almost at our time. I want to be conscious of everyone's timing and not try to go over. So with the little bit of time that we have left, I do want to see if there's any questions out there. If anyone wants to put them in the Q&A or into the chat, wherever, happy to answer any questions that we have in our remaining time. And while I give you that remaining time, let's actually just go ahead real quick and push this all up to GitHub, so that way, if you want to play around with this afterwards, you can have the source code for everything. So let's just go ahead. Ah, what's the header collapse for? So that is allowing us to take this secondary header that we created, and scrolling, as we scroll up, we can start to collapse that into the initial header and show that instead. Let's go ahead and commit this first. git add, git commit, commit. And then we'll create a repo, update. Up create. git push origin name. And then that is the URL for the repo. Check it out when you have a moment. We do have a question. How do you handle... exists in the web? That's a really great question. This is something that we do inside of Capacitor. We actually, inside of the Capacitor community, have this project called PWA. Is it in Capacitor project? Capacitor PWA. It's actually in, I forget where it was. Let's load it up real quick. Ionic PWA elements. So we actually have this complementary package called PWA elements. If we look at the GitHub repo for it, it basically comes with a few different UI elements to help fill the gap in certain cases. So for instance, if we are using Capacitor without Ionic and we want to have an action sheet, we can provide that. Same thing with a toast or camera. If there's other components that don't exist in there that you would like to see, please open up an issue for it. But we also give you a chance to be able to conditionally handle situations where you're on those platforms. So you could just say, if I'm on web, don't try to render this. Hopefully that answers your question, Andrew.
19. Plugins and Native Functionality
Plugins are a way of wrapping native functionality in a consumable package. The media package allows working with native media APIs. The iOS plugin provides native methods and implementation details. A simple wrapper is provided for web targeting. The plugin automatically calls the appropriate native API based on the platform. If you want to know more about building plugins, please reach out to us. Check out the capacitor site for resources and details. Visit ionicframework.com/react for more on the React version. Questions are welcome before concluding the session.
And could I please talk more about plugins? Of course. So plugins themselves are actually our way of taking up native functionality and wrapping that in a consumable package. So a real good one that we can look at that isn't too complex is this media package. So this media package allows you to take, what's it called? It allows you to take in, you know, save a photo, save video, create albums, basically allows you to work with all the media APIs that are available to a native device.
So the way this works is we have this iOS plugin, which basically gives you all of the different methods that you could want to create in the native portants of it. Not gonna dive too much into native code because I'm not a expert in native code. So I wouldn't want to give you misinformation, but in this case, we have all of the native details that are happening behind the scenes. So in iOS, this is going to call a site, get media, get albums, and then here's our implementation for how we can actually save those albums taking the data that we're passing along to it and calling the necessary native APIs for that. When we want to go ahead and actually target that from the web, we provide this real simple wrapper or not wrapper, but these real simple interfaces for the plugin, so we can share all of the different implementation details whether or not that is in the Java implementation or in the Swift implementation. So you get all the type safety and then when SetCalled is made, because of how the plugin gets registered, it automatically knows, hey, I'm calling this API and I'm on iOS, so call this native API. We have some really good docs on how you can actually build out your own plugins, but if this is something that you would like to, if you would like to know a little bit more about, please tweet at us. I'd love to know because this would make an excellent blog post. I wanna know if that's something that other people would read versus me just hoping people would want it.
Okay, so, I'll update. I posted the repo for everybody. If you have any other questions, please post them. Otherwise, if you wanna learn more about this stuff, you can check out the capacitor site at capacitorjs.com. It has all of the resources and details for getting started and going into even further details into the plugins, especially the native APIs. And if you want to check out more about IONIQ and specifically the React version, we have this excellent little landing page that you can go check out, called ionicframework.com slash react with some great code examples and some material to get started and some material that we get up and running with. So at the time we are a little bit over, so I want to be conscious of that. So I'll stop sharing my screen. If you have any other questions, please ask now otherwise you're free to go.