 Hello. Welcome to Absolutely Necessary, Powering Mobile Apps with Drupal. For agenda today, we're going to talk about mobile apps. Why they're considered mobile apps and why they're important. Architecting, we're going to touch on various mobile architecture approaches and Drupal's role, where we'll discuss leveraging what Drupal does best and modules that help use Drupal as a backend for your mobile app. But first, let's introduce ourselves. I'm Amy Novica, a software developer, and I'm here with Greg Schoenfeld, a software architect, and we're phase two. A good portion of you probably already know us as we've been in the Drupal community for 20 years. But if you haven't heard of us, we're a digital product agency passionate about consumer experience grounded in data insights and rooted in two decades of successful technology delivery. We make digital products that inspire, engage, and create impact. Along the way, we guide industry leaders towards what's next in their digital landscape. So, what are mobile and native apps? Mobile apps are downloaded from an app store or similar marketplace and installed on a device that includes phones, tablets, or wearables, and the most popular operating system for these are iOS and Android. So, I'm sure most of you know many, many mobile apps, but allow me to give you some examples along with features that make them unique. So, one good mobile app is an American Museum of Natural History Explorer app. What it does is it leverages location and wireless technology to allow visitors to learn more about the exhibits that they're actively experiencing as well as be a virtual guide throughout their tour. Another good app is Robinhood, which takes the complexity of trading stocks and simplifies the flow, allowing a wider variety of individuals to trade stocks when the markets open from anywhere. Additionally, if you're someone who's active, we have MyFitnessPal, which allows individuals to set diet or exercise goals and keep track of them through either location or Bluetooth pairing to wearable devices. And Home Depot apps shows the customers exactly where to find the product they're looking for on a specific shelf alongside a map of the store they're actively in. Also, probably the most complex mobile apps are games like Candy Crush, Pokemon Go, Angry Birds that make use of super complex technologies like artificial intelligence or augmented reality, so that you can have a much easier and addicting time-crushing candy or well, throwing some Angry Birds at pigs. And then we have Native Apps, which can also be downloaded from the respective app stores or even preloaded by manufacturers of the system. Now, these systems can be over the top like Roku, TVOS, Android TV, Fire TV, Xbox, your little brother's PlayStation, mainly like any consoles or smart TVs. But also, Native Apps can be Mac, Windows, or Linux-based as well. Usually, desktop apps are built in Electron, which is NodeJS-based, Tori, which is Rust-based, or similar frameworks. Some examples of popular OTT apps would be Netflix, Hulu, HBO Max, usually streaming media. However, if you're someone who doesn't really like to watch Netflix and chill with your friends, these options aren't only limited to video. You can also have audio apps like SoundCloud or Spotify. For desktop apps, there are plenty and likely you already use some. We have Skype, Slack, Discord, if you're a gamer, and even Visual Studio Code, all of which that I just listed are built using Electron that uses JavaScript and web languages. So, you might be asking yourself, why native and mobile apps? Well, they provide new marketing and customer acquisition channels that regular websites may not be able to. These apps will appear on app stores that have their own opportunity for store optimization in a similar concept to search engine optimization. These apps may also be the first point of entry for customers looking for your product, as well as individuals, as well as, sorry, my bad. These may be the first point of entry for customers looking for your product, and usually these customers actually go to the app stores first rather than searching on a Google engine. So, it can be the very first point of entry for users to be able to see what you have created. Additionally, they allow you to leverage your customer's most powerful devices. Unless you're a developer or maybe an avid gamer, the most powerful device that you'll have is likely gonna be your smartphone. So, it's important to use the features of the customer's most powerful device. And some of these features include location services. So, you can tailor the needs of the customer based on where they actively are and where they're going. This also includes payments, which allow you to leverage things like Google and Apple Pay, which are directly integrated into the device and enable a much easier payment flow. Additionally, you can provide offline capabilities so your customers can experience your services even in times without internet coverage in a much more seamless way than the web could provide. These are just some of the features that can be leveraged with native and mobile apps. Another important advantage is the easy pathways you can create to help customers complete transactions. For example, if there's a complex process such as booking an appointment or a difficult payment, you can provide them with a very streamlined flow. Unlike browsers that have many distractions with various in-web functionalities, native and mobile apps can have a much more streamlined navigation, what a spelled out user flow. All the while leveraging the features that we just mentioned to make the whole experience much more efficient and effective. So when it comes to digital product strategy, mobile apps play a large role. Not only can they be the single point of entry, they can also complement what you currently have on the web. Whenever you're thinking about building a mobile app, you should consider having some unique features in that mobile app. Things like Amy mentioned as complex purchases and designed user flows are just one way to kind of have enhanced presentation for your company. As you're going through a complex booking flow, sometimes if you're booking an appointment for a hospital visit or doctor visit, sometimes you need to have the ability to get a specific type of appointment and the user probably doesn't need to know what that actually is at the end of the day. So by providing guided questions, you can go through and create a way to dictate what journey they need to have without actually telling them what that is. Along with this, the misconception is that a website and a mobile app should be the exact same. However, users are not expecting the exact same user and user experience between those two platforms. As you use mobile apps like Android, they have a specific feel to them and iOS has a different specific feel and if you provide a user with an iOS experience on Android or vice versa, customers will end up losing trust with you because they have something that doesn't feel like what they're used to. These are very important to do and a lot of people miss that and they try to make one user experience for both platforms. However, there are experiences that you need to have for both. So apps should be a compliment to your website but not necessarily a direct clone. So how do we build apps at phase two? There are three main approaches. So there is a cross platform. So these are frameworks like React Native and Flutter. There's also native script but we don't use native script. These are a right once published everywhere for the most part. Then we have native that will be Swift for iOS and Kotlin for Android and then there's BrightScript for Roku. And then the third option is like a hybrid web in PWA. So I kind of lump these three all together. Frameworks for those are gonna be like Ionic and Cordova. Cross platforms are the most effective from a development perspective on building an app. Basically with these frameworks you can write one code base that happens to be in JavaScript and then from there it turns it down into native technologies that can be shipped to the app store. This is really important to differentiate between PWAs that can also be written in web languages but they are not shipped to the app store. Almost always with cross platform apps you have to write some native code. You're never gonna get away with writing a large enterprise app without writing some native code. A lot of these functionalities with the APIs are available by third party contributions from the communities but there's always gonna be something that you need for a specific device as you come through that can require you to go down and write that actual native code. Previous generations of React Native had issues with performance. They've since done a complete rewrite of the architecture under the hood and now you don't have to worry about the performance degradation between the two. They're coming so close that it's really hard to differentiate a true native app versus a cross platform app. One other piece that you do get with cross platform is you have access to everything that you would have on the device if you were writing a true native app. The only difference is how hard it is to get to that technology. So native apps. These are going to be written in, like I said, Swift for iOS and Apple platforms that also includes TVOS and Mac apps can all be written in Swift. That is the Apple's preferred method of development. There's Objective-C but that has been since pretty much deprecated because of the drastic difference in time to do development. Google platforms use Kotlin and Java. Again, Java is being deprecated as the not preferred language because of speed. I will mention that Kotlin can also be done as a multi-platform. So you can actually write a Kotlin app that will compile down to iOS. It is in a very, very early stage but it is possible. One concern with native apps is you must have two completely discrete teams on building these apps and they have to try to stay in sync. There are very few people that can write both Android and iOS at the same time efficiently. These people do exist, they're very expensive, they're very hard to come by. So in this process, you have to maintain both the cadence of releases for operating systems. So Android and iOS do not release operating systems at the same time. So you may have an upgrade for one and not the other and then you'll have to try to keep the feature parity as you keep going through. This is the most performant option because the APIs are direct in the languages and you don't have to write a layer of abstraction between the two. As you go through this though, the one thing is this is probably the most expensive way of building a mobile app because you have to have two discrete teams and we're talking teams of five to 10 people on each side for iOS and Android specifically. So third option, this is the hybrid and web PWA space. So I know a lot of people think PWAs are like the first thing that comes to mind when you come from web tech into a mobile app. PWAs are not the silver bullet for these because every platform behaves a little bit differently with what they support for PWAs. When you write a PWA, you are, PWA stands for Progressive Web App. When you write a PWA, you are actually just wrapping your website in a mobile browser and then saving that to the user's home screen, which is just basically a shortcut to exact same kind of technology. The only differentiator is that it has a service worker that allows you to do things like offline mode under the hood. There are lots of different platforms that can offer PWAs, so React, View, Angular, Pick a framework. There's also specific frameworks like Ionic that allow you to do this out of the box. So it is a fast way to get to market, but it is not a dedicated mobile app because you cannot put one of those in the app store. And Apple still has a bad relationship with PWAs. They are not supported as much as they are on Android. Along here, there's also the option of doing like a quote what we call a hybrid app, which is an app that's built with native technologies and then everything is web viewed in from a website. This can work, but you do end up hitting a ultimate like ceiling of what you can accomplish. Each of the web views are a subset of the native browser. So it doesn't matter which browser you use on an iPhone, it's still powered by Safari and WebKit. However, the web view, you still have a limitation of what APIs you have access to. So you may not be able to get Bluetooth or you may not be able to get hyper local precise locations without a huge layer of abstraction and big expense. And sometimes they're actually not available at all. With a traditional web app, these are things that where you write a web app and then you just ship the mobile version and then you have the user access them in a browser. These again are not ideal because you still don't have access to the same APIs that you would have with the traditional native apps. Now here is where Drupal gets mentioned for the first time. So this is our model of bring whatever you have and we'll serve it to your consumers. So at the top of this chart, you have your content or CMS. We have media, we have custom APIs and databases. So anything you have, we can work with and then bring into your mobile app. So custom APIs, things like Salesforce, NuleSoft, Epic EHRs, other custom EHR systems for electronic health records. These are all examples of things that we can consume with an application service and then serve up to your mobile app. From the application service layer in the middle, that is where we provide APIs for the apps to consume. This is our traditional decoupled architecture that you've probably seen for decoupled Drupal sites. However, we're talking about just consuming it for a mobile app. So application services serves as a way to manipulate the data in a way to get it consumable for the app. So your Drupal site can always stay the same for whatever CMS you're using. So for the actual application service, it is just a middleware between your app and for content, your media, your other APIs. What this allows us to do is normalize the data and present only what we need. So we typically leverage GraphQL to do this. The reason for this is we can specify easily exactly the data we need and we don't have to worry about over-fetching with a huge rest query. We can write a bunch of discrete queries to get exactly the pieces that we need. Another benefit of writing the application service in between is the ability to obscure sensitive API tokens. So anything that you compile into the app gets shipped to the user. So if you put an API key in your code base, it's gonna end up being shipped to the user and technically someone can decompile reverse engineer and grab your API token. By allowing us to have this application service, we allow a one-way communication to the service, to the sensitive service by running it through the application service and using a Kajido VT to pass it between the two. This allows us to prevent things like a PHI to be stored on the user's device. That's always a concern, same thing with financial data or anything, the II, personal identifier information. So by doing, even like layer in between, we're allowed to kind of separate the two worlds between the user, the client side, and then the server side where all the business logic lives. Also by putting the business logic outside of the app, it's easier, you can ship features without having to actually ship a new version of the app because you can write it in the business layer and then as long as the app knows how to consume whatever you're spitting out, you don't have to worry about that. Also in the application service, we typically have application configuration this is typically, this can be saved in either Drupal or in another system as a custom database, but the app will speak to the application service, figure out what configuration, what features it needs, and then respond to that and display that to the user. One more thing is the caching. So depending on your APIs that you have, APIs have rate limits typically, and what you can do is you can have the application service call your API for you and as long as it isn't super real-time data, like search results, like booking slots don't typically work because you have, some slot could be gone, but you have that ability to cache things in between where you are and that way you don't have to worry about hitting a rate limit on APIs. This is a common occurrence we've run into. So how does Drupal play into this now? So we've gone over what mobile apps are, gone over some architecture behind them, and while this being DrupalCon, you're probably wondering, how does Drupal actually play a role in all of this? So Drupal is more than just a content management system. It's able to handle translations, media, internationalization, and database views that help with custom queries. With these, Drupal can be implemented as a data source, either directly through Drupal's APIs or through a middleware, like an application service that we just discussed about earlier. However, directly calling Drupal as a backend source has a lot of benefits. Probably the biggest and most obvious one is that it's much easier and faster to implement than using a middleware. You would have a direct line of communication to your data source rather than needing another service or system in place. On top of that, you can leverage the skills that you already know. If you're experienced with Drupal, then using its APIs won't require as much learning when compared to figuring out a middleware application service. And Drupal's core REST API gives you multiple formats that you can use off the bat, such as XML, JSON, and Hall JSON. Drupal is flexible enough that you can store any type of key values in its database. This allows us to store configurations for runtime in Drupal and have an interface that can be modified by content editors in order to enable or disable features within the app based on what the environment requires. But we all know Drupal isn't just about its core functionalities. It has a large open-source community full of valuable core and fantastic contrib modules. So to name a few of those that would be valuable in powering mobile apps, we have GraphQL, a great contrib module that enables complete control of the GraphQL schema. It provides full support of the official GraphQL specification with all its features, including reading and writing through queries and mutations. There's also the RESTful Web Services core module that enables you to expose entities as REST resources to allow a native or mobile app to talk to a Drupal site. With following that, we have the JSON API core module, which implements the JSON API spec for the Drupal entities just mentioned. And to top it all off with another fantastic contrib module, we have DructsDrupal modules. These Dructs modules greatly simplify decoupled development, making powering mobile apps that much easier. Now we're gonna talk about a case study that we've used for phase two. So we built a large enterprise mobile app for Northwell Health. Northwell Health, if you do not know, is a very, very large hospital system in New York. There are over 70,000 employees, along with 800 hospitals and care centers in the Long Island area. As being one of the largest healthcare systems in the US, we're able to build them a app using all of the services that we talked about before. And it's been a long multi-year process to help create their digital patient experience. So the application does consume Drupal, so there is content served from Drupal, there is also content served from another CMS, sandy.io, that uses all of our configuration. Discrete teams worked on discrete pieces of this, and that's why we were not able to just use Drupal to just handle everything. But by decoupling everything, we were able to talk to different teams and not have to worry about one team owning something and then trying to integrate them together. It has a highly personalized experience and the ability to see your patient records, to schedule appointments, to find care, or providers you may or may not have seen before. Location services, messaging services to tell you like real time, like appointment reminders, text message services. This app in particular uses Gigia as our authentication provider, which is a completely custom provider that we had to integrate with native code. There is a lot of native code under the hood for Gigia. So these are all the SDKs you have to work with on a regular basis to do like complex integrations like that. From this experience, they've been able to gather, oh, sorry, yeah. So booking appointments are probably one of the biggest ones they were doing to get access to their clients or to their new patients. So there was lots and lots of iterations provided to get ways to book and make it easier for users. And that's where the custom booking flows came into place in that we needed a way for a non-developer to have a way to build a flow in order to get it into the hands of a user faster than us having to spend weeks getting into a backlog and then turning into a release. So by using configuration in a CMS, we were able to drop the time from three sprints, so six weeks to a single sprint, and that we knew right away when it needed to be done, we could spit it out and it could go live in the next two weeks. Because Northwell has so many providers, they have over 4,000 physicians in their system, they needed a robust search, so they have their own search algorithm they use that they own from scratch, and then we had to communicate with that via GraphQL on our application service in between those layers. And all of this, the way we did it was we were able to stick all the GraphQL queries in configuration so that we also, again, we could make the changes to serve up different data without having to push a new version to the app store. One consideration always is when you publish a new version, you have to make sure it's backwards compatible unless you're gonna force your user to update, and that was one thing that typically people would never wanted to do then with the force and update, so backwards compatibility is always a challenge. Another piece they added was Consolidated Bill Pay and Chatbot integrations. These allow them to collect money quickly and then have users be able to access information that they may not be able to find easily, they may be looking for something specific, they are able to add a Chatbot that allows us to help guide them in the right journey. This is another way that we've able to provide pathways into finding different places. Text stack of what Northwell uses. Drupal, of course, for Content, Apple, for the iOS support, Android for the Android support, Pigea, InterSystems, Experian for Patient Identification, Cerner for the support of the scheduling system, Taylor, which does the payments, or forms processing, HealthPay 24's payments, follow my health, is their tracker for test results, built with Azure and Docker to deploy with Node.js as the app service, React Native as the underlying application technology, and AppCenter for the build process of compiling the apps and then shipping them to the respective app stores, and then finally, Acquia for hosting of their Drupal instance. So, are you our next client partner seeking an enterprise mobile or OTT app? Agency partner looking to expand your offering to be OmniChannel or a passionate mobile app developer looking to work with the latest technologies at phase two. Find us at booth 333 to learn more about mobile app development and other new technologies that we're working on, such as Outline, as well as how we can help your next project be a success. And we have some time for questions. There's two mics, one in the middle and one over there on that side. Hey, how you doing, Daniel with MDVIP? So, thanks for the presentation, very relevant to some of the stuff that we're doing as well. Part of the challenge with GraphQL middleware that we're experiencing and the React team is not supporting blue-green deployments and on the Acquia platform and so forth. And you solve one of the problems is by storing the queries outside of the apps, which probably help a lot, which I'm gonna look into. What are some of the recommendations you can give for, I would say early development on React Native, we've recently transitioned to and we're having challenges, coordinating and not delaying the graph work because of the apps, because the business does not want to, for example, deploy builds as often, force app updates and so forth, same thing. Other than using contracts or Poly Federation and so forth. Yeah, so definitely in that case, we had basically two sets of GraphQL queries at some point that whereas version one lived there, version two lived there and that's how we ended up moving to the configuration option because we knew that we had to support back two versions. So we had like unknown cadence. In your case, you said that the business does not want to release very often. That's a challenge in itself, because you're gonna have to have the ability to try to get those updates out. But when you're thinking about it, I think the best way is sticking the queries themselves in essentially they live in a database, essentially there's a string of a giant GraphQL query. It's not ideal, but it was the only option that we found that we could support backwards compatibility because we can deploy at any time the application service and make changes there without having to go through like a formal deployment process. So I think that's probably the first thing is start thinking that way of what can I offload to essentially like a database where I can have a key value pair and then bringing it back and then having your Apollo on the client side, do we go be like, hey, I got that app configuration at the beginning of the app. But when we initialize the app, you get the app config. And then when we bring it back, basically you're like, okay, I know I need to run this query, go get the data and then bring it back. Okay. One more question. Yeah. There's nobody else. Go ahead. So doing progressively decoupled Drupal applications, we're doing React.js on the front end, hitting GraphQL, also doing twig with hitting GraphQL in some cases, right? And how do I put this? How do you standardize to make sure the developers are naming the queries consistently because the fact of GraphQL, you can name your own methods, your own queries, right? It becomes a big disconnect and using Apollo Graph Manager, which is a great tool, then you get like different consumers calling the same thing differently, right? Incorrectly in many times. So have you experienced that and how do you solve it? I mean, this is the classic problem of naming things as hard, right? I think the biggest thing is communication between your teams that when you're, if you're gonna go make a new query or modify a query, go look at Apollo, figure out, go look in your GraphQL playground, figure out what's already there and what's not. In our case, we had one team that was managing all of the GraphQL, so it wasn't a huge deal, but they were also the biggest consumer of it, so that was why they were the ones who owned that piece of it. But other departments were also calling it, but it was just one piece that was in charge of the entire graph. Got us. You don't have like a guidelines documentation or anything like that. Yeah, like typical guidelines for like, here's how you name things, right? And we had like, here's how you name classes, here's how you name functional components, et cetera. So we just have like a general guideline of here's how you name things, but enforcing that is nearly impossible, I determined. So again, it's that naming problem, typical programming, naming things as hard. And then you're using JWT for authentication, right between the system you said. So having the JWT exposed in the network on the client side, it's not a security issue at whatsoever. No, cause you need the other half of it, right? So JWT isn't a big deal. You need the private key to match it. Yep, I understand. Okay, so never came across any compliant issues. Okay, thanks. All right, thank you. Hello. Yep, hey, so I just wanted to share, I just wanted to share an approach we've been using. It was pretty interesting. We have like an e-commerce application website that's the kind of point where I'm trying to say websites and application. React Native Web, super awesome, saved us a ton of time, saved our development team a ton of time, complicated checkout and just building that, using React Native Web. React Native Web allows you to like basically take a React Native application. They do it kind of what you might consider backwards, which is not, cause it's mobile first. It'll take like the React Native code and then output HTML, which is awesome because we would change something like super complicated checkout logic and then we would have to, like you said, the two different teams and now with React Native Web, we basically have one team where we combined our teams now cross functional and working across the board. So I just wanted to share that with everybody. It's pretty cool way. We've done something similar in that we basically ripped all of the logic out of the, like it was a React app. We ripped all the logic out of all the components and then we stored that as like a shared piece. So then everything that was like presentational was either written by React or React Native. It worked out well. It was difficult to do that, like the first step of ripping everything apart so that you had like your smart components, your dumb components. But once you had like that layer in between, you were able to just go ahead and write either a React or a React Native. And then when we did the compile process, it knew like which components to grab. Yeah, and we did that with the mono. We did that in the beginning and using NPM and everything was hard. But have you, setting up a mono repo, the hot reloading and everything, it's awesome because our app and our website is in the same repo and you have them both up. You make a change in the shared folder and everything just updates and you can kind of see it in the simulator and everything, so. No, definitely a good approach. It's a pretty cool workflows, yeah. Yeah, we should talk more about that, though. Hey, Greg, hey, Amy. I was just, yeah, there's no other real people who have questions. So, other. Not that you other people are all fake, but, you know. Actually, cardboard cutout, two dimensional. Don't look at this side. But other than going against a Sicilian when death is on the line, what are some of the classic blunders in your opinion that people make with us and they should not do? All right, the one thing is trying to force an Android experience onto iOS or an iOS experience onto Android. I think that's the biggest one. Yeah, like if you just immediately assume PWAs are the only way to go and just straight up copy it to the mobile experience, you're gonna have a very bad time. Especially the users are gonna have a bad time trying to figure out how the app works. It's because they're not used to having the browser on their phone. They're used to an app for their flow. Yeah, and I think kind of dovetailing to that is the trying to do the hybrid approach where you're just webframing in a bunch of things. Like there is a place and time to use a web view for certain features. Your entire app is not the feature. Definitely you hit a ceiling of what you can actually accomplish and then you kind of have to be like, well, now what? Because if you didn't invest in the technology to actually do some native work in between, you're gonna end up having to basically start over. Another thing is if you are just gonna webframe in a bunch of things, at least do the effort to remove the header in the footer because you really don't need that in the mobile app because you already have a navigation system. Because what's gonna happen is you will end up like getting off into some random place in your website and never hear how you got back to where you started from. And especially you have to do link management because some links, if you just have just Ahrefs in your web app, they will just take you out of the app into some random website and the user might not even have a way to get back, which we've seen happen sometimes and it's terrible. I'm Ujwal from et cetera. So I have a question for transition data. How do you manage that transition data and the caching management at the React or GraphQL? Any challenge or? All right, so let's start with the translation piece. Basically, whenever we make the calls to whichever, if it's REST or a GraphQL, we typically just pass in the language as a parameter in there so we're able to get it that way. And then you mentioned caching. In that case, caching's hard, right? It's the same concept. What we end up typically doing is managing the cache on the application service. And then if we have to flush it, it's only in one place, but we know that that is the single source of truth. So we need to make sure you determine where your source of truth is because if you have multiple layers that can be cached, so if you have a Drupal site that also has a couple of caches, you can also run into problems of having stale data. So just make sure you, if you're gonna flush the cache of the application service, know that you're gonna get whatever's in the Drupal cache at that moment, not necessarily whenever you go and update that site. So I think that's kind of the biggest one. Also, setting appropriate length time on your caches is also very important because some things can live forever. Some things need to be updated pretty frequently. You can also do things where you check to make sure what needs to be, like when the last time it was cached, you can do some polling. We've also used subscriptions to update data that way as well in GraphQL. Obviously that's not supported by the Drupal module at the moment, but real-time data in Drupal is not typically something that we see. If you're gonna do something real-time, you don't want anything cached in that layer. My name is Paul. I have a question about offline stuff and I'm curious if you've done that at all and if you have any experience using a PWA versus native and if one is easier. Yes, Amy made me able to talk about this one a little bit more than me, but definitely we've done it. In the offline mode, with native, you're able to store much more information into like a stink storage on the devices and it allows you to persist it way longer. So you can persist hours, essentially permanently, in the ability to cache things that way. When you run into a PWA, you don't have control over the cache as much. So with native, I can say, okay, dump the cache. With a PWA, you're at the mercy of what the browser does. So if your phone decides that it's full and it wants to dump the cache, it could dump the cache at any moment. Yeah, and for iOS specifically, they have a separate PWA container for storage. iOS has 500 megabytes for their storage and you don't have any control over when you can dump it. I think deleting the app might actually clear the storage but it's not like the documentation is not clear at all, it had to control it. And then the async storage or local storage on the web that you access on the mobile app is very regular. It does not go into that same container. It goes who knows where and it can reset itself when it wants. It's much harder to control when it comes to a PWA. For Android, I don't think the issue is as big but it's just there are a lot of restrictions that are out of the developer's control when it comes to PWA's. Sorry I'm back. We have this one weird edge case. Just wanted to see if you could experience it. With React Native WebView on Android, when we're signing out of our IDP because we're limited with our horrible IDP, that's no API based, we have to use the browser. For some reason, Android's WebView handles it different than iOS and we're losing the connection so we have to force the user to close the browser to re-initiate. Is this something you've run across? Cause it just sounds like a weird Android bug but. It is a weird Android bug for sure. I haven't run into it. I had the unfortunate experience of having to write a SAML setup like both sides in node because it doesn't exist anywhere. So similar concept like where we ran into the problem of Android does have that issue of it loses the connection. iOS is definitely better handling the handoff between the two. But yeah, there's definitely that weird bug. Like we've run into a lot of strange behaviors between the two platforms. And that handoff with the WebView is definitely one of them. The only option is switch providers. I mean, that's not a real answer. I understand. Well, at least you helped me save the time and not wasting more time and figuring out an alternate solution. Yeah, there's no alternate solution other than like. Close the browser. Or figure out if that method is public, which I don't think it is. Cause I think we tried the same thing. It's protected, yeah. So get on the phone with Google. I mean, if you have connections, a lot of apps have a Google partner that can help you. Sure. Maybe it's a try to be like, hey, this is not working. Let's see if we can figure out how to get it to work. All right, so don't use Salesforce IDP check. Yeah. We have five minutes. Any more questions, anybody? We don't have any questions and thank you all for coming. I'm just glad to have you all. Please visit us at booth 333. If you have any questions that may come up after you leave or if you wanna learn more about phase two and what we do.