<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Max Lynch</title>
    <description>The latest articles on Forem by Max Lynch (@maxlynch).</description>
    <link>https://forem.com/maxlynch</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F77831%2Fdd90b1ab-73fc-4b3a-a63b-3e824eaccc27.jpeg</url>
      <title>Forem: Max Lynch</title>
      <link>https://forem.com/maxlynch</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/maxlynch"/>
    <language>en</language>
    <item>
      <title>10 Reasons to Choose Ionic for Mobile Development</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Thu, 22 Jul 2021 18:47:57 +0000</pubDate>
      <link>https://forem.com/ionic/10-reasons-to-choose-ionic-for-mobile-development-213a</link>
      <guid>https://forem.com/ionic/10-reasons-to-choose-ionic-for-mobile-development-213a</guid>
      <description>&lt;p&gt;The &lt;a href="https://ionicframework.com/"&gt;Ionic&lt;/a&gt; stack makes it easy to build iOS, Android, Desktop, and Progressive Web Apps using standard web technology. There are a lot of options for cross-platform mobile and web app development, so when should you or your team consider using Ionic?&lt;/p&gt;

&lt;p&gt;Here are 10 reasons you might want to choose Ionic:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. You’re a web developer
&lt;/h2&gt;

&lt;p&gt;One of the best reasons to choose Ionic is if you’re a web developer and want to stay in the web development world. The Ionic stack is built on standard web development technologies meaning you can build the majority of your app directly in a browser and use standard browser development tools and technologies, while still deploying and building a traditional native app.&lt;/p&gt;

&lt;p&gt;Other cross-platform toolkits don’t use the web development stack so aren’t the best fit for web developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. You are building a new app dev engineering team
&lt;/h2&gt;

&lt;p&gt;Because the Ionic stack is focused on web developers, it’s the easiest cross-platform technology to hire for because there are considerably more web developers in the world than any other mobile technology. Any web developer can easily learn to build apps using the Ionic stack and it will be the most familiar to them, and have the best compatibility with popular web frameworks like React, Angular, and Vue.&lt;/p&gt;

&lt;p&gt;And hiring web developers means they can then develop for mobile, desktop, and web without the need to hire specialist teams for each platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. You’re an enterprise (or work at one)
&lt;/h2&gt;

&lt;p&gt;Ionic is the only cross-platform development stack that has &lt;a href="https://ionic.io/"&gt;Enterprise support and integrations&lt;/a&gt; for teams building employee and customer-facing apps. Ionic offers dedicated support, security features like &lt;a href="https://ionic.io/products/identity-vault"&gt;Biometrics&lt;/a&gt; and &lt;a href="https://ionic.io/products/auth-connect"&gt;Single Sign-on&lt;/a&gt;, and cloud services for &lt;a href="https://ionic.io/appflow"&gt;remote app updates, app builds, and app store distribution&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ionic is the industry leader in enterprise app development with hundreds of Fortune 1000 customers, and &lt;a href="https://www.g2.com/products/ionic/reviews"&gt;customers love it&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. You have existing web experiences and investments
&lt;/h2&gt;

&lt;p&gt;Because the Ionic stack is based around standard web development, it’s the only cross-platform solution that supports bringing existing web experiences, libraries, and other web code into an app.&lt;/p&gt;

&lt;p&gt;This is particularly important for enterprises or teams with a heavy web presence that want to bring those experiences into existing apps, such as traditional native apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. You want to join a massive community of developers
&lt;/h2&gt;

&lt;p&gt;Building apps with popular technologies makes it easier to hire for, easier to find partners, and easier to find resources on the web as you build your app.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://ionicframework.com/community"&gt;Ionic developer community&lt;/a&gt; is massive, with millions of developers around the world having built apps on the stack. Passionate community members build and share tutorials, add-ons, templates, and more, and developers can find help on the &lt;a href="https://forum.ionicframework.com/"&gt;Ionic forum&lt;/a&gt; and Stack Overflow.&lt;/p&gt;

&lt;p&gt;But Ionic is unique in that the community isn’t just limited to Ionic’s bubble. Because Ionic is based on standard web technologies, the addressable community goes beyond Ionic and overlaps with the broader web development community, such as the React, Angular, and Vue communities. This is critical when considering building out app dev teams because an Ionic team can be built with web developers, but other technologies require hiring specialists on languages and technologies that are not widely used.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. You’re on a tight deadline
&lt;/h2&gt;

&lt;p&gt;We often hear from teams who spent months building their app using a different technology, failed to hit deadlines, and then switched to Ionic and had the new app working and surpassing the old one within weeks.&lt;/p&gt;

&lt;p&gt;Ionic is highly productive because the web is highly productive. And one app can run on multiple platforms so development time can be upwards of 3-4x faster than traditional native development!&lt;/p&gt;

&lt;h2&gt;
  
  
  7. You want your apps to be on iOS, Android, Web, and even desktop on day one
&lt;/h2&gt;

&lt;p&gt;Ionic apps run anywhere the web runs, and with the same code! And Ionic has official support for iOS, Android, Desktop, and Web, so teams can hit the ground running — targeting all these platforms and their respective user bases at launch.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. You want to be able to benefit from both app store &lt;em&gt;and&lt;/em&gt; web traffic
&lt;/h2&gt;

&lt;p&gt;Because the Ionic stack is based on web technology, teams can target the web and build a high-performance Progressive Web App (PWA).&lt;/p&gt;

&lt;p&gt;This means teams can reach users both in traditional app stores but also on the web and through Google search to maximize reach and have the best chance for a successful app project. We’ve &lt;a href="https://dev.to/ionic/app-store-or-web-why-not-both-3fa2"&gt;talked at length&lt;/a&gt; about how the Ionic stack gives you the best distribution optionality of any cross-platform technology in the market.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. You already have web developers on your team
&lt;/h2&gt;

&lt;p&gt;If you already have web developers on your team or at your company, using the Ionic stack is a no-brainer! Web developers can easily become mobile developers by learning to use the Ionic stack, including Ionic’s &lt;a href="https://ionicframework.com/docs/components"&gt;100+ mobile-optimized UI components&lt;/a&gt; and &lt;a href="https://capacitorjs.com/"&gt;the native runtime&lt;/a&gt; that provides hooks into functionality on each platform. Ionic also supplies the means to build and deploy those apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. You’re a student or new to app development
&lt;/h2&gt;

&lt;p&gt;Ionic is the most accessible platform for cross-platform app development. If you’re familiar with basic web development you can build real mobile apps (and desktop + web apps) today! &lt;/p&gt;

&lt;p&gt;Learning Ionic requires learning a few new HTML tags, some new JavaScript APIs for native functionality, and then just building your app using your framework of choice (React/Angular/Vue/etc).&lt;/p&gt;

&lt;p&gt;And the best thing is you continue to build your web development skills at the same time and don't have to change your technical career focus.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started today
&lt;/h2&gt;

&lt;p&gt;There you have it, ten good reasons you and your team might want to adopt Ionic.&lt;/p&gt;

&lt;p&gt;If you're interested in building cross-platform apps using Ionic and modern web technologies, &lt;a href="https://ionicframework.com/"&gt;Get started&lt;/a&gt; with Ionic today.&lt;/p&gt;

</description>
      <category>ionic</category>
      <category>mobile</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>App store or web? Why not both!?</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Wed, 09 Jun 2021 16:12:23 +0000</pubDate>
      <link>https://forem.com/ionic/app-store-or-web-why-not-both-3fa2</link>
      <guid>https://forem.com/ionic/app-store-or-web-why-not-both-3fa2</guid>
      <description>&lt;p&gt;Most app development technologies force teams  to make hard decisions about where they will distribute their apps, usually either app stores as a native app or the web as a Progressive Web App.&lt;/p&gt;

&lt;p&gt;Building a native Swift (iOS) or Kotlin (Android) app, for example, obviously limits teams to just those respective platforms. But others have more subtle restrictions. Xamarin enables you to build for iOS, Android, and Desktop, but not for the web, meaning no access to a major chunk of mobile traffic and app-consuming users. React Native’s View elements can be abstracted to have the same API on the web but you will need to write completely separate view code for it, avoid using certain standard web features, and use different calls for certain APIs, so it’s an additional investment. Flutter can be used to build iOS, Android, and Web apps, but its web support requires multiple MBs of code for users so it’s not appropriate for high-performance Progressive Web Apps and speed-sensitive web sites like those that depend on search engine rankings and SEO.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://capacitorjs.com/"&gt;Capacitor&lt;/a&gt;, a universal app runtime, avoids these tradeoffs by targeting one universal runtime (the web), and giving you maximum optionality for where you distribute the app that you build. You can deploy your app with one codebase anywhere your users are, even if that happens to change! That might mean the app stores today, but it could mean the web and desktop tomorrow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Optionality Looks Like
&lt;/h2&gt;

&lt;p&gt;I was recently helping a team think through an app project they were going to deploy to the app stores on iOS and Android. They were using Capacitor with React, using a home-grown UI based on Tailwind. &lt;/p&gt;

&lt;p&gt;During development, the team decided that they wanted to have a strong web portion to their app in order to easily acquire users, benefit from instant access and SEO on the web, and avoid app install bounce risk (meaning, the user leaves without ever installing the app, which is very common in the mobile world!)&lt;/p&gt;

&lt;p&gt;Since their app was built with &lt;a href="https://capacitorjs.com/"&gt;Capacitor&lt;/a&gt;, utilizing Capacitor’s &lt;a href="https://capacitorjs.com/docs/plugins"&gt;cross-platform APIs&lt;/a&gt;, they could simply deploy the same app with the same code as a Progressive Web App hosted on a platform like Vercel or Netlify.&lt;/p&gt;

&lt;p&gt;And this decision didn’t preclude them from also shipping a native iOS and Android app. They decided that they would unlock some additional features that depended on native functionality missing from the browser environment for users that were “activated” and likely to stick around.&lt;/p&gt;

&lt;p&gt;Doing so in Capacitor was straightforward because Capacitor APIs are identical on iOS, Android, and the Web, and Capacitor comes with a &lt;a href="https://capacitorjs.com/docs/core-apis/web#isnativeplatform"&gt;number of utilities&lt;/a&gt; for adding conditional platform-specific code if desired.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this Matters
&lt;/h2&gt;

&lt;p&gt;For new projects, the greatest risk isn’t technical but rather that no one uses your app and it never gains meaningful traction or scale. One of the best ways to avoid that is to reach the broadest possible segment of your target audience on day one.&lt;/p&gt;

&lt;p&gt;For most companies, their audience isn’t on a single platform, form factor, or environment (such as mobile or web). This is especially true for consumer and enterprise consumer companies. In fact, there’s a good chance a majority of users aren’t even on a platform that you, the developer, actually use primarily (such as Android if you’re an iPhone user or web apps if you’re in the US and used to installed native apps).&lt;/p&gt;

&lt;p&gt;Having optionality might mean the difference between your app project failing or succeeding, and nothing could matter more than that.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does this compare to Progressive Web Apps?
&lt;/h2&gt;

&lt;p&gt;One of the things to think about when building a Progressive Web App &lt;em&gt;not&lt;/em&gt; with Capacitor, is that it will constrain your app to running only in a traditional browser context. This means it will only be accessible on the web and not have the option to access native APIs that don't have a browser analog since it cannot be distributed in popular mobile app stores.&lt;/p&gt;

&lt;p&gt;Thus, the decision to build a Progressive Web App can also be limiting. But in this case a very straightforward way to add native iOS and Android support is by installing Capacitor into your Progressive Web App. &lt;/p&gt;

&lt;p&gt;Capacitor has &lt;a href="https://capacitorjs.com/docs/web"&gt;full Progressive Web App support&lt;/a&gt; and apps use the same Capacitor API calls regardless of the platform they are running on. This makes it easy to bring it to iOS and Android with the same code.&lt;/p&gt;

&lt;p&gt;In that sense, Capacitor is "web app virtualization layer" that enables standard web apps to run anywhere with the same APIs, regardless of the "host" platform underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who's using Capacitor today?
&lt;/h2&gt;

&lt;p&gt;Capacitor is growing quickly (100% YoY) and is installed &lt;a href="https://npmcharts.com/compare/@capacitor/core"&gt;over 500k times per month&lt;/a&gt;. Teams at companies like Burger King, Tim Hortons, Workgrid (Liberty Mutual), and Fidelity, to name a few, are all using Capacitor to enable their web teams to deploy iOS, Android, and Web apps with the same code.&lt;/p&gt;

&lt;p&gt;Capacitor was also rated &lt;a href="https://2020.stateofjs.com/en-US/technologies/mobile-desktop/"&gt;#1 in satisfaction among mobile development tools&lt;/a&gt; on the latest State of JS survey.&lt;/p&gt;

&lt;p&gt;Capacitor was created by the team behind the popular &lt;a href="https://ionicframework.com/"&gt;Ionic Framework&lt;/a&gt; as a  replacement for Cordova for deploying modern &lt;a href="https://webnative.tech"&gt;Web Native&lt;/a&gt; apps on iOS, Android, Desktop, and Web.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Getting started with Capacitor and building full distribution optionality into your mobile-enabled web app is as easy as installing the Capacitor library and running a few commands.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://capacitorjs.com/docs"&gt;Get started&lt;/a&gt; with Capacitor today and &lt;a href="https://twitter.com/capacitorjs"&gt;follow us&lt;/a&gt; for more resources and updates on the project!&lt;/p&gt;

</description>
      <category>ionic</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Building a better Web View for mobile apps</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Tue, 18 May 2021 15:02:21 +0000</pubDate>
      <link>https://forem.com/ionic/building-a-better-web-view-for-mobile-apps-183</link>
      <guid>https://forem.com/ionic/building-a-better-web-view-for-mobile-apps-183</guid>
      <description>&lt;p&gt;Web Views are among the most widely used components in mobile apps for good reason: most apps need to incorporate some internal or external web experience at some point.&lt;/p&gt;

&lt;p&gt;Because of this, Apple and Google provide basic Web View controls out of the box:  iOS with &lt;code&gt;WKWebView&lt;/code&gt;, and Android with &lt;code&gt;WebView&lt;/code&gt; (there are other options on Android but this is the primary one most apps use).&lt;/p&gt;

&lt;p&gt;Unfortunately, using these Web Views is anything but simple, and native developers are stuck reinventing the wheel every time they need to use one of these Web Views in their app. Luckily, that pain is coming to an end. Read on to learn about &lt;a href="https://ionic.io/portals"&gt;our take&lt;/a&gt; on a better drop-in Web View for iOS and Android native app developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Use case for Web Views
&lt;/h2&gt;

&lt;p&gt;Web Views feature prominently in many apps. Some apps are built entirely around a single primary Web View instance, and other traditional native apps selectively display and embed Web Views to bring in web experiences.&lt;/p&gt;

&lt;p&gt;For apps where most of the functionality and content is built in the Web View, the use case for Web Views is obvious. I don’t want to spend more time talking about that use case here but tools like &lt;a href="https://capacitorjs.com/"&gt;Capacitor&lt;/a&gt; and &lt;a href="https://ionicframework.com/"&gt;Ionic Framework&lt;/a&gt; excel at this and are widely used.&lt;/p&gt;

&lt;p&gt;For traditional native apps, the use cases for embedding web experiences might vary from from embedding an existing web experience such as a mortgage application or a survey, to displaying web-based authentication forms, to hosting prototype web experiences before porting to native.&lt;/p&gt;

&lt;p&gt;Generally, the more established the company, the larger their web development teams, and the more prominent that company is on the web, the more likely they will need to bring in web experiences into their mobile app at some point in time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Web Views Today
&lt;/h2&gt;

&lt;p&gt;Generally, Web Views provided by Apple and Google are spartan and bare bones. Nearly every native developer that we’ve talked to has expressed annoyance at extending the stock Web View controls and then maintaining a fairly complex set of code to host web experiences in the app. Thus, the problem with the stock Web Views is that they just don't do enough and don't cover the surface area of what native developers typically need them to do.&lt;/p&gt;

&lt;p&gt;I have first-hand experience with this as the creator of &lt;a href="https://capacitorjs.com/"&gt;Capacitor&lt;/a&gt;, which is essentially a supercharged Web View for hosting web apps that need to interface with existing native code. Capacitor is many tens of thousands of lines of code that wrap the core Web Views available on each platform and add a number of features, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An API for adding new native “plugins” that expose new Web APIs to web developers based on custom native code, and do so in a controlled fashion and with a web-developer approved API (promises, typescript, etc)&lt;/li&gt;
&lt;li&gt;A high performance bridge for communicating between web and native and keeping track of invocations and returning results back to the caller&lt;/li&gt;
&lt;li&gt;Handling references to assets to host web content offline and correctly stream data for Web HTML controls like video and audio (surprisingly tricky).&lt;/li&gt;
&lt;li&gt;Marshalling data between the native and web layer&lt;/li&gt;
&lt;li&gt;Managing native elements such as alert dialogs, keyboard, status bar, scroll regions...all while correctly handling orientation changes&lt;/li&gt;
&lt;li&gt;Handling delegate methods for navigation, load, errors, permission requests, and other general housekeeping.&lt;/li&gt;
&lt;li&gt;Updating embedded web experiences dynamically and out of band with the slower native release cycle&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And then doing this on both iOS and Android (on which even more code and complexity is required). And this list is not nearly exhaustive!&lt;/p&gt;

&lt;p&gt;It seems like every meaningfully large native app ends up implementing a subset of the features above, which is no small task!&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a better Web View
&lt;/h2&gt;

&lt;p&gt;It took many months to build the first version of Capacitor due to the complexity required in building a robust Web View wrapper with the above features, and I never want another developer to have to go through that again.&lt;/p&gt;

&lt;p&gt;Sadly, almost every native app developer does have to go through this today, and then has a bunch of complex, custom code to maintain. All that when they could have just imported a stable, well maintained, feature-rich Web View control and got back to the fun part of building their app.&lt;/p&gt;

&lt;p&gt;When we realized that what we had with Capacitor could be pulled out to help native app developers everywhere, we knew we were on to something: a much better Web View for native apps. &lt;/p&gt;

&lt;h2&gt;
  
  
  Announcing Ionic Portals
&lt;/h2&gt;

&lt;p&gt;We’ve been working on bringing the Web View technology behind Capacitor to native apps and native developers everywhere, and we are taking the wraps off the first iteration of that product today: &lt;a href="https://ionic.io/portals"&gt;Ionic Portals&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ionic Portals is a drop-in Web View component for native apps that handles all the messy, annoying parts of using a Web View in a native app. Developers can host multiple different web experiences through different “portals”, and isolate them, selectively exposing custom native functionality that each one needs. Teams can remotely update and deploy new web experiences dynamically to deploy new features and tests in realtime and without disrupting the native app release process.&lt;/p&gt;

&lt;p&gt;Ionic Portals uses the same technology currently deployed in major consumer apps like Burger King, Paylocity, H&amp;amp;R Block,  Aflac and more, but distributed as a drop-in control for existing native apps.&lt;/p&gt;

&lt;p&gt;And on top of all this, Ionic Portals is maintained and supported by us, so you have one less component to have to maintain in your app.&lt;/p&gt;

&lt;p&gt;We’re currently working with a few teams who are desperate for a better Web View control in their native apps. If you’re interested in trying it out and sharing your feedback as we built out the product, we’d love for you to get in touch. Visit the &lt;a href="https://ionic.io/portals"&gt;Ionic Portals page&lt;/a&gt; to see a demo and learn more about our take on a dramatically improved Web View for native apps.&lt;/p&gt;

</description>
      <category>android</category>
      <category>ios</category>
      <category>swift</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Build Mobile Apps with Tailwind CSS, Next.js, Ionic Framework, and Capacitor</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Mon, 01 Feb 2021 15:24:54 +0000</pubDate>
      <link>https://forem.com/ionic/build-mobile-apps-with-tailwind-css-next-js-ionic-framework-and-capacitor-3kij</link>
      <guid>https://forem.com/ionic/build-mobile-apps-with-tailwind-css-next-js-ionic-framework-and-capacitor-3kij</guid>
      <description>&lt;p&gt;A very popular stack for building responsive web apps is &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt; and &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt; by &lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Tailwind, a utility-first CSS framework that replaces the need to write custom class names or even any CSS at all in many cases, makes it easy to design responsive web apps through small CSS building blocks and a flexible design foundation.&lt;/p&gt;

&lt;p&gt;Next.js, a React framework for building high performance React apps, is one of the leading environments for building production React apps on the web.&lt;/p&gt;

&lt;p&gt;As these technologies have grown, they are increasingly used together for web app development (in fact, Next.js is working on an &lt;a href="https://github.com/vercel/next.js/discussions/20030" rel="noopener noreferrer"&gt;RFC for official Tailwind integration&lt;/a&gt;). This has prompted many users of these projects to ask whether they can be used to build mobile apps, too.&lt;/p&gt;

&lt;p&gt;Turns out, they can! And they make a great fit for cross-platform mobile development when paired with &lt;a href="https://ionicframework.com/" rel="noopener noreferrer"&gt;Ionic Framework&lt;/a&gt; and &lt;a href="https://capacitorjs.com/" rel="noopener noreferrer"&gt;Capacitor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As I started playing with these technologies, I realized that each had a natural fit in a combined mobile stack, and I wanted to put together a solid starting foundation for others interested in building real iOS and Android apps using these technologies.&lt;/p&gt;

&lt;p&gt;If you're confused by all the project names and how they work together, don't worry, I'll break down each part of the stack each project is concerned with, along with some visuals and code samples demonstrating how all the projects work together. At the end I'll share &lt;a href="https://github.com/mlynch/nextjs-tailwind-ionic-capacitor-starter" rel="noopener noreferrer"&gt;a starter project&lt;/a&gt; with these technologies installed and working together that can form the foundation of your next app.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack Visualized
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbwhawidkv6ju58h8rdqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbwhawidkv6ju58h8rdqw.png" alt="Diagram of layers in a Capacitor Tailwind Next.js Ionic app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above is a live screenshot of a React app built with Next.js that is using Ionic Framework and Tailwind for the UI experience, and Capacitor to natively deploy that app to iOS and provide access to any Native APIs the app uses.&lt;/p&gt;

&lt;p&gt;There are a lot of projects working in tandem to provide the full experience here. To visualize it, I've tried to overlay the different layers and how they correspond to each project in this diagram above.&lt;/p&gt;

&lt;p&gt;We can see that Capacitor is concerned with the entire app and device layer of the app, Next.js is concerned with the entire web/React app our code and UI is running in, then Ionic handles the "platform UI" including navigation toolbar (including system title and toolbar buttons) as well as the bottom tabs.&lt;/p&gt;

&lt;p&gt;Finally, Tailwind is used to then style and customize the content of each page, which is where the bulk of the app-specific styling will occur.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mobile UI and Native Runtime
&lt;/h2&gt;

&lt;p&gt;If your experience building with web technologies is primarily for desktop or responsive sites, you might not be familiar with mobile-focused libraries Ionic Framework and Capacitor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ionicframework.com/" rel="noopener noreferrer"&gt;Ionic Framework&lt;/a&gt; is a cross-platform, mobile-focused UI library for the web. It provides ~100 components that implement platform UI standards across iOS and Android. Things like toolbars, navigation/transitions, tabs, dialog windows, and more. The big draw is those components work on the web and work in frameworks like React, Angular, Vue, or plain HTML/CSS/JS.&lt;/p&gt;

&lt;p&gt;Ionic Framework is highly popular and powers upwards of 15% of apps in the app store.&lt;/p&gt;

&lt;p&gt;Historically, Ionic Framework would be paired with a project like Cordova which provided the native iOS and Android building and runtime capabilities. However, most new Ionic Framework apps use Capacitor for this part of the stack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://capacitorjs.com/" rel="noopener noreferrer"&gt;Capacitor&lt;/a&gt; is a project built by the team behind Ionic Framework focused on the &lt;em&gt;native&lt;/em&gt; side of a web-focused mobile app.&lt;/p&gt;

&lt;p&gt;Capacitor provides a plugin layer and runtime that runs web apps natively on iOS, Android, Desktop, and Web, and provides full access to device APIs and features (including extending the web environment by writing additional native Swift/Java code).&lt;/p&gt;

&lt;p&gt;As such, any popular web technologies and libraries can be used to build mobile apps with Capacitor, and then deploy the same apps with the same code to the web and desktop.&lt;/p&gt;

&lt;p&gt;And, to top it all off, Capacitor was just &lt;a href="https://2020.stateofjs.com/en-US/technologies/mobile-desktop/" rel="noopener noreferrer"&gt;rated the second highest in satisfaction&lt;/a&gt; among popular Mobile &amp;amp; Desktop Tools on the State of JS 2020 Survey! If your last experience with this mobile development approach was with Cordova, we think you'll find Capacitor to be a big improvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing the Next.js + Tailwind CSS + Ionic Framework + Capacitor Starter
&lt;/h2&gt;

&lt;p&gt;Now that you have a sense for how these technologies all work together to make it easy for web developers to build mobile apps, let's take a look at a real demo and starter project (&lt;a href="https://github.com/mlynch/nextjs-tailwind-ionic-capacitor-starter" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foxj2evycaakr0r8q5pvc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Foxj2evycaakr0r8q5pvc.png" alt="Next.js Tailwind Ionic Capacitor Starter"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's take a look at the main Feed page (seen above in the screenshot) for an example of how the different technologies in use work together:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;IonPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;IonHeader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;IonToolbar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;IonTitle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;IonButtons&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;IonButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;IonIcon&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;IonContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ionic/react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;notificationsOutline&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ionicons/icons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Notifications&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./Notifications&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../ui/Card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getHomeItems&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../store/selectors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Store&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../../store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FeedCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authorAvatar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;image&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Card&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-4 mx-auto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rounded-t-xl h-32 w-full object-cover&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;px-4 py-4 bg-white rounded-b-xl dark:bg-gray-900&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h4&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-bold py-0 text-s text-gray-400 dark:text-gray-500 uppercase&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h4&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;font-bold text-2xl text-gray-800 dark:text-gray-100&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sm:text-sm text-s text-gray-500 mr-1 my-3 dark:text-gray-400&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flex items-center space-x-4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;authorAvatar&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rounded-full w-10 h-10&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h3&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text-gray-500 dark:text-gray-200 m-l-8 text-sm font-medium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h3&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Card&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Feed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;homeItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getHomeItems&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;showNotifications&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setShowNotifications&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonPage&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonHeader&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonToolbar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonTitle&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Feed&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonTitle&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonButtons&lt;/span&gt; &lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonButton&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setShowNotifications&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonIcon&lt;/span&gt; &lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;notificationsOutline&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonButton&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonButtons&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonToolbar&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonHeader&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonContent&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ion-padding&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;fullscreen&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonHeader&lt;/span&gt; &lt;span class="nx"&gt;collapse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;condense&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonToolbar&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonTitle&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;large&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Feed&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonTitle&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonToolbar&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonHeader&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Notifications&lt;/span&gt;
          &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;showNotifications&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;onDidDismiss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setShowNotifications&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;homeItems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FeedCard&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonContent&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonPage&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Feed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As we can see, we use Ionic Framework controls (&lt;code&gt;IonPage&lt;/code&gt;, &lt;code&gt;IonHeader&lt;/code&gt;, &lt;code&gt;IonContent&lt;/code&gt;, &lt;code&gt;IonToolbar&lt;/code&gt;, etc) for the structure of the page (these controls implement iOS and Android platform-specific styles and navigation/transition behavior), then we use Tailwind for the page content that is where our custom design lives (which will tend to be in &lt;code&gt;IonContent&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;If we look at another page that is just a simple list, we see that we don't use Tailwind at all, because the user would expect this page to be a standard iOS/Android list and toggle button (&lt;a href="https://github.com/mlynch/nextjs-tailwind-ionic-capacitor-starter/blob/main/components/pages/Settings.jsx" rel="noopener noreferrer"&gt;code here&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdpxgbwh5x2tt6dfn5pu7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdpxgbwh5x2tt6dfn5pu7.png" alt="Settings Page Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, we tend to use Tailwind more for pages with a lot of custom design and assets. That's by design. Generally when building a native mobile app, we want to use platform conventions as much as possible, especially for experience and performance-sensitive elements like Lists, Toolbars, Tabs, and Form inputs. However, for the &lt;code&gt;Feed&lt;/code&gt; page, which has a pretty custom UI experience, we end up getting a lot of mileage out of Tailwind.&lt;/p&gt;

&lt;p&gt;So, in general, the way to think about when to lean more on Ionic Framework and when to lean on Tailwind is when your UI experience will heavily use typical mobile UI elements (prefer Ionic components) or when it will be more custom (prefer Tailwind).&lt;/p&gt;

&lt;p&gt;Finally, this starter also comes with a few small opinions around folder structure and state management. For state management, the library &lt;a href="https://lostpebble.github.io/pullstate/" rel="noopener noreferrer"&gt;pullstate&lt;/a&gt; is used which is a simple yet powerful state management library with a hooks-based API (I wrote &lt;a href="https://dev.to/ionic/pullstate-simple-hooks-based-state-management-for-react-5bc4"&gt;more about it here&lt;/a&gt;). If want to use something else, removing it is easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying to iOS and Android
&lt;/h2&gt;

&lt;p&gt;The app can be easily deployed to iOS and Android using Capacitor and its local CLI tools. After running &lt;code&gt;npm install&lt;/code&gt;, you'll have the &lt;code&gt;npx cap&lt;/code&gt; command available, which enables a &lt;a href="https://capacitorjs.com/docs/basics/workflow" rel="noopener noreferrer"&gt;native development workflow&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;To add an iOS or Android native project:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx cap add ios
npx cap add android


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, to build the Next.js app, export it, and copy it to the native projects:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm run build
npm run &lt;span class="nb"&gt;export
&lt;/span&gt;npx cap copy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This command is needed every time the built output changes. However, you can enable livereload during development (see the &lt;code&gt;README&lt;/code&gt; for more info).&lt;/p&gt;

&lt;p&gt;Then, you can launch Xcode and/or Android Studio to build and run the native project:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;p&gt;npx cap open ios&lt;br&gt;
npx cap open android&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Next steps&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;If you've been interested in building mobile apps using popular web dev projects like Next.js or Tailwind, hopefully this starter provides inspiration and a solid foundation for building your next app using web technologies. It's worth mentioning this exact same approach can be used with other UI libraries (like material, bootstrap, or your own!).&lt;/p&gt;

&lt;p&gt;When you're ready, dig into &lt;a href="https://github.com/mlynch/nextjs-tailwind-ionic-capacitor-starter" rel="noopener noreferrer"&gt;the starter project&lt;/a&gt;, follow the &lt;a href="https://capacitorjs.com/" rel="noopener noreferrer"&gt;Capacitor&lt;/a&gt; and &lt;a href="https://ionicframework.com/" rel="noopener noreferrer"&gt;Ionic Framework&lt;/a&gt; docs, and get building!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tailwindcss</category>
      <category>javascript</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>The Easiest Way for Web Developers to Build Mobile Apps</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Tue, 05 Jan 2021 15:45:13 +0000</pubDate>
      <link>https://forem.com/ionic/the-easiest-way-for-web-developers-to-build-mobile-apps-1ih8</link>
      <guid>https://forem.com/ionic/the-easiest-way-for-web-developers-to-build-mobile-apps-1ih8</guid>
      <description>&lt;p&gt;For web developers interested in building Mobile apps, there's a plethora of options today. Developers can choose between projects like React Native, NativeScript, Cordova, Ionic Framework, and Capacitor, just to name a few.&lt;/p&gt;

&lt;p&gt;Given the large number of options, it's not always clear  what would be the most appropriate for a web developer looking for a familiar web-based development experience.&lt;/p&gt;

&lt;p&gt;With that, I'd like to make the case that &lt;a href="https://capacitorjs.com/" rel="noopener noreferrer"&gt;Capacitor&lt;/a&gt; (optionally with a mobile-focused UI framework like &lt;a href="https://ionicframework.com/" rel="noopener noreferrer"&gt;Ionic Framework&lt;/a&gt;) is the most natural and easiest way that web developers can build mobile apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Electron for Mobile"
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://electronjs.org/" rel="noopener noreferrer"&gt;Electron&lt;/a&gt; is a massively popular solution for building cross-platform desktop applications using standard web technologies. Web Developers can use the standard HTML, CSS, and JavaScript they use for web apps, including any popular libraries like React/Angular/Vue, Tailwind, or Material UI, and turn those apps into powerful desktop apps.&lt;/p&gt;

&lt;p&gt;This simple formula has turned Electron into one of the most popular cross-platform toolkits. Today, Electron powers many popular apps, like Slack and VS Code.&lt;/p&gt;

&lt;p&gt;If you ever find yourself asking "what is the analog to Electron but for mobile apps?" the answer is &lt;a href="https://capacitorjs.com/" rel="noopener noreferrer"&gt;Capacitor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Like Electron, Capacitor takes a standard web app that runs in the browser, and extends it with access to powerful native APIs and Native UI (like &lt;a href="https://capacitorjs.com/docs/apis/camera" rel="noopener noreferrer"&gt;Camera&lt;/a&gt; and &lt;a href="https://capacitorjs.com/docs/apis/filesystem" rel="noopener noreferrer"&gt;Filesystem&lt;/a&gt;). These APIs work on iOS, Android, Web, and Electron.&lt;/p&gt;

&lt;p&gt;While Electron bundles in a "web view" through Chromium, Capacitor uses the standard embedded Web View native controls available on iOS and Android. This means that Capacitor doesn't suffer from the same bloat issues that Electron does.&lt;/p&gt;

&lt;p&gt;The net effect is that Capacitor is really a sort of  "Electron for Mobile."&lt;/p&gt;

&lt;h2&gt;
  
  
  What about React Native or Flutter?
&lt;/h2&gt;

&lt;p&gt;You might be asking yourself: why isn't React Native (or Flutter) the "Electron for Mobile?"&lt;/p&gt;

&lt;p&gt;The reason is that React Native and Flutter do not use a standard web browser environment to run an app. Rather, they are abstractions over system UI controls and APIs to provide a "web-like" experience building apps rather than a true web environment. Both require code specifically written for each platform, and cannot use web-specific libraries or code.&lt;/p&gt;

&lt;p&gt;This is important, because it means the shortest path for a web developer to build a mobile app is Capacitor, hands down:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy47oq2g4ida5ztgdhvsu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy47oq2g4ida5ztgdhvsu.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  An Example
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftq6nt1p40o4877d7664w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftq6nt1p40o4877d7664w.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's take a &lt;a href="https://github.com/mlynch/ionic-react-example" rel="noopener noreferrer"&gt;simple example&lt;/a&gt; of a web app using Ionic Framework with React for a native-quality mobile UI experience, and Capacitor to deploy it natively to iOS, Android, and web.&lt;/p&gt;

&lt;p&gt;Taking a look at the &lt;a href="https://github.com/mlynch/ionic-react-example" rel="noopener noreferrer"&gt;code&lt;/a&gt;, we see that it's just a plain React app that happens to use Ionic Framework for its UI components. For example, developers familiar with React Router should find the &lt;a href="https://github.com/mlynch/ionic-react-example/blob/master/src/App.tsx#L37" rel="noopener noreferrer"&gt;JSX used to build the Tab layout&lt;/a&gt; familiar.&lt;/p&gt;

&lt;p&gt;Then, by running some Capacitor commands, we can bundle the app and run it right in Xcode:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsnmo35hui27kz7mqmdhn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsnmo35hui27kz7mqmdhn.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since our app is just a plain React app, we can also run it directly in the browser and even deploy it as a Progressive Web App to any static web host:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9j9p4mb9x0d6oei667oh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9j9p4mb9x0d6oei667oh.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, Capacitor ships with a JS module, &lt;code&gt;@capacitor/core&lt;/code&gt;, that provides a consistent, cross-platform approach to accessing device functionality. &lt;/p&gt;

&lt;p&gt;For example, to access the &lt;code&gt;Filesystem&lt;/code&gt; API, we can use the same code on iOS, Android, Web, and Electron:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="nx"&gt;Plugins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;br&gt;
  &lt;span class="nx"&gt;FilesystemDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
  &lt;span class="nx"&gt;FilesystemEncoding&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@capacitor/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Filesystem&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Plugins&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fileWrite&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Filesystem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secrets/text.txt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This is a test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FilesystemDirectory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Documents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
      &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FilesystemEncoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UTF8&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;br&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wrote file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unable to write file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Who's using Capacitor?&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Capacitor is being used to power major apps today. Companies like Burger King, Popeyes, and the BBC (who wrote a &lt;a href="https://medium.com/bbc-design-engineering/shipping-progressive-web-apps-everywhere-190a421c606a" rel="noopener noreferrer"&gt;great article&lt;/a&gt;  about their use of Capacitor to build universal, web-native apps) are using Capacitor build apps across iOS, Android, Web, and Desktop with one code base and standard web technology.&lt;/p&gt;

&lt;p&gt;Capacitor is also the new native foundation of &lt;a href="https://ionicframework.com/" rel="noopener noreferrer"&gt;Ionic Framework&lt;/a&gt;, which powers over 15% of all apps in the app store today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with Capacitor
&lt;/h2&gt;

&lt;p&gt;If you're familiar with Electron, Capacitor should feel very familiar to you. It's installed like a typical JS module directly into your app, and a local CLI tool is added for copying your web app to native iOS and Android projects, as well as syncing and installing new Capacitor plugins.&lt;/p&gt;

&lt;p&gt;To get started with Capacitor, check out the official &lt;a href="https://capacitorjs.com/docs" rel="noopener noreferrer"&gt;Capacitor Docs&lt;/a&gt; and get building!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>ionic</category>
    </item>
    <item>
      <title>What is it about Vue?</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Mon, 19 Oct 2020 16:06:24 +0000</pubDate>
      <link>https://forem.com/ionic/what-is-it-about-vue-1j7n</link>
      <guid>https://forem.com/ionic/what-is-it-about-vue-1j7n</guid>
      <description>&lt;p&gt;On the heels of announcing &lt;a href="https://ionicframework.com/blog/announcing-ionic-vue/" rel="noopener noreferrer"&gt;official Vue support for Ionic Framework&lt;/a&gt;, I wanted to dig into why we decided to officially support Vue here at Ionic, and why we’re so excited about it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But first, if you aren’t familiar with Ionic, we make popular open source projects like &lt;a href="https://ionicframework.com/" rel="noopener noreferrer"&gt;Ionic Framework&lt;/a&gt; and &lt;a href="https://capacitorjs.com/" rel="noopener noreferrer"&gt;Capacitor&lt;/a&gt;, focused on enabling web developers to build award winning mobile apps with their existing web development skills and libraries. Ionic Framework provides a cross-platform UI toolkit focused on the visual aspect of a quality mobile experience, and Capacitor provides a cross-platform runtime and plugin API to access the full native functionality your app needs on each platform it runs on. Use them together or use Capacitor with any web-based UI framework for mobile!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many developers know Ionic Framework as a mobile toolkit for Angular. And while we fully support Angular today, in the last few years we’ve branched out to supporting React, and now Vue.&lt;/p&gt;

&lt;p&gt;It’s no small task for us to officially support a framework. While Ionic Framework’s web components work in any web technology, integration with framework-specific tooling like Routers, CLIs, and more is where the bulk of the work comes, so choosing to support a framework officially is a big deal for us.&lt;/p&gt;

&lt;p&gt;Why, then, do we feel it is crucial to support Vue? And why do we feel that Ionic Framework + Vue brings unique value to the ecosystem and an experience that lives up to our goals as a project?&lt;/p&gt;

&lt;h2&gt;
  
  
  “The best of React and Angular”
&lt;/h2&gt;

&lt;p&gt;Ionic Framework was initially built around AngularJS (that’s the 1.x version) back in 2013. What drew us to AngularJS back then was the ability to incrementally adopt it in any web app, extend HTML with powerful control flow constructs (loops, conditionals, etc), create essentially new HTML tags powered by JS, and easily apply it to any size app from small to enterprise-scale.&lt;/p&gt;

&lt;p&gt;While Angular 2 evolved from the original approach taken in AngularJS, doubling down on its focus on large, complex enterprise apps (the kind Google and other large companies build), those original features of AngularJS that drew so many to it in the beginning fell out of favor in exchange for a monolithic solution focused on building large apps from scratch.&lt;/p&gt;

&lt;p&gt;When talking to Vue developers, one way they frame why Vue is so great is it essentially perfected that early approach in AngularJS, creating something fundamentally new and compelling along the way. It’s no surprise then that so many Ionic 1.x developers who used AngularJS back then were drawn to Vue when the Angular 2 fork in the road appeared, and picked it up very quickly.&lt;/p&gt;

&lt;p&gt;Vue developers often contrast it with React as well, appreciating more powerful data binding (especially with forms), compilation-free templating that uses standard HTML (i.e. no JSX required), and the batteries-included approach where key libraries for routing and state management are officially supported and maintained by the Vue team.  &lt;/p&gt;

&lt;p&gt;Add these up and it’s clear why many Vue developers consider it to be the best of both worlds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vue is exploding
&lt;/h2&gt;

&lt;p&gt;With all the benefits above, it’s no wonder that Vue has found itself a passionate developer base that wasn’t satisfied with the binary Angular or React decision tree and tradeoffs.&lt;/p&gt;

&lt;p&gt;That developer base is absolutely exploding, with some metrics, like stars, growing faster than React and nearly any other project on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuc1n8ct6otb6chp1wxqo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuc1n8ct6otb6chp1wxqo.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While stars are a vanity metric, there’s proof that this popularity has fostered a strong ecosystem of Vue-specific addons, projects, and frameworks. Vue-specific web app frameworks like Nuxt.js and Gridsome add powerful Jamstack features to the Vue ecosystem. UI libraries like Vuetify, and mobile solutions like Quasar, NativeScript, and Ionic Vue provide options for building engaging UI experiences with Vue across nearly any platform.&lt;/p&gt;

&lt;p&gt;It’s clear that Vue is a force to be reckoned with and any web library like Ionic that purports to support the key frameworks web developers are using simply has to take it very seriously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ionic Framework and Vue is a perfect match
&lt;/h2&gt;

&lt;p&gt;One of the most common questions we received over the last two years has been “when is Vue support for Ionic Framework coming out?” In fact, we received that question so often that it became a meme inside the company, with us often taking bets on how long it would take for someone to ask about Vue support on any given tweet or blog post (even if it had nothing to do with Vue!)&lt;/p&gt;

&lt;p&gt;Obviously, the Vue ecosystem has been hungry for more mobile app development solutions. While a few solutions already exist for building mobile apps with Vue, including NativeScript Vue and Vue Native, what Ionic Framework brings to the table is a mobile development solution that is much more web centric. When you build with Ionic Vue, you’re able to target native iOS and Android with a &lt;a href="https://medium.com/@maxlynch/cordova-ionic-apps-are-native-apps-64f9e1a995d9" rel="noopener noreferrer"&gt;truly native app&lt;/a&gt; that gives you full access to the native device and any native API. At the same time, you get the benefit of a UI layer that is truly web, so any existing web libraries, vue add-ons, UI components, or CSS styles will fit right into your Ionic Vue mobile app. Plus, as a bonus you can deploy your Ionic Vue mobile apps as pure mobile web apps or PWAs.&lt;/p&gt;

&lt;p&gt;Ionic is focused intensely on web developers using popular web development technologies, with a massive community, and with support and features for serious apps and enterprise teams. To add on to that, Ionic Framework is backed by a &lt;a href="https://ionic.io/" rel="noopener noreferrer"&gt;growing company&lt;/a&gt; that is focused exclusively on commercializing Ionic Framework and its companion native runtime project, Capacitor. &lt;/p&gt;

&lt;p&gt;From a developer experience standpoint, Ionic and Vue have similar roots. Both were inspired by AngularJS to some extent, and both focus on empowering web developers to build incredible things with the technologies they already know, with a low barrier to entry. Vue’s approach of using standard HTML in templates pairs incredibly well with Ionic Framework’s move to Web Components at the core, so using Ionic components feels like any other HTML tag, only with magic mobile powers.&lt;/p&gt;

&lt;p&gt;Finally, Ionic is immensely popular, powering &lt;a href="https://appfigures.com/top-sdks/development/apps" rel="noopener noreferrer"&gt;nearly 15% of all app stores&lt;/a&gt;, and has become synonymous with “mobile for web developers.”&lt;/p&gt;

&lt;h2&gt;
  
  
  The future is Bright for Vue
&lt;/h2&gt;

&lt;p&gt;The technical challenges and long term maintenance concerns that come with choosing to officially support a framework for Ionic Framework are significant. We will invest considerable resources, financial and otherwise, to support any new framework integration in Ionic Framework.&lt;/p&gt;

&lt;p&gt;We have decided to fully embrace and support Vue starting with Vue 3, because we think it is increasingly a pillar of the web development ecosystem, and will only grow in importance and relevance over time.&lt;/p&gt;

&lt;p&gt;We also think it spiritually aligns incredibly well with our values and approach with Ionic Framework. We believe in the web platform. We believe in enhancing HTML, CSS, and JavaScript and enabling web developers to do incredible new things with it. Vue helps teams build and orchestrate the functionality and rendering of their app, and Ionic Vue helps those teams make their Vue apps feel great on mobile.&lt;/p&gt;

&lt;p&gt;If you’re curious about Ionic Vue and want to try building iOS, Android, and Progressive Web Apps using Vue 3 and all the Vue-compatible web libraries you know and love, take a look at &lt;a href="https://ionicframework.com/docs/vue/quickstart" rel="noopener noreferrer"&gt;Ionic Vue&lt;/a&gt;!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hey, you there! Want to build a mobile app with Vue but already have a UI library or can't use Ionic Framework's UI controls? Check out &lt;a href="https://capacitorjs.com/" rel="noopener noreferrer"&gt;Capacitor&lt;/a&gt;. It's the native runtime part of the Ionic stack that runs any web app on mobile regardless of what it was built with.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>vue</category>
      <category>ionic</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Pullstate - Simple hooks-based state management for React</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Mon, 21 Sep 2020 22:25:53 +0000</pubDate>
      <link>https://forem.com/ionic/pullstate-simple-hooks-based-state-management-for-react-5bc4</link>
      <guid>https://forem.com/ionic/pullstate-simple-hooks-based-state-management-for-react-5bc4</guid>
      <description>&lt;p&gt;State management is one of the most important pieces of an app, and there are a ton of choices for those in the React ecosystem.&lt;/p&gt;

&lt;p&gt;In particular, developers building iOS and Android mobile apps with React using &lt;a href="https://capacitorjs.com/"&gt;Capacitor&lt;/a&gt; and &lt;a href="http://ionicframework.com/react"&gt;Ionic React&lt;/a&gt; often ask us for state management recommendations. Of course, there's Redux, which I remain a &lt;a href="https://medium.com/@maxlynch/redux-is-the-pivotal-frontend-innovation-a406736552cb"&gt;major fan of&lt;/a&gt;, but also much simpler state management approaches like MobX and &lt;a href="https://ionicframework.com/blog/a-state-management-pattern-for-ionic-react-with-react-hooks/"&gt;rolling your own using the Context API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I've spent a lot of time using Redux and also the bespoke approach with the Context API. Yet, I wasn't satisfied. I wanted to find something that was simple but high performance, and had native integration with Hooks and Function components which I now use exclusively in React (sorry, never want to write the word &lt;code&gt;class&lt;/code&gt; ever again 😆).&lt;/p&gt;

&lt;p&gt;That's when I stumbled on &lt;a href="https://lostpebble.github.io/pullstate/"&gt;Pullstate&lt;/a&gt;. Pullstate is a small, relatively unknown library (just 300 stars at the time of this writing), but I expect it will become much more popular in time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring Pullstate
&lt;/h2&gt;

&lt;p&gt;Pullstate provides a simple Store object that is registered globally, and provides hooks for accessing data from that store in a component:&lt;/p&gt;

&lt;p&gt;store.ts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;StoreType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;currentProject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Project&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MyStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Store&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;StoreType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
 &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;currentProject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;MyStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in your component, simply use the &lt;code&gt;useState&lt;/code&gt; method provided on the store to select data from the store:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MyStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Modifying state
&lt;/h2&gt;

&lt;p&gt;To update state in the store, use the &lt;code&gt;update&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;MyStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;update&lt;/code&gt; function works by mutating a Draft of the state. That draft is then processed to produce a new state.&lt;/p&gt;

&lt;p&gt;Usually, a state mutation would raise a red flag, but the magic of Pullstate comes from a really interesting project called &lt;a href="https://github.com/immerjs/immer"&gt;Immer&lt;/a&gt;. Immer essentially proxies an object and then turns mutations on that object into a new object (in my limited experience with it). Sort of how the vdom does diffing to figure out a new DOM tree.&lt;/p&gt;

&lt;p&gt;This is incredibly powerful and simple, but does have a few gotcha's. First, reference comparisons on objects in the &lt;code&gt;s&lt;/code&gt; value above will fail, because they are actually &lt;code&gt;Proxy&lt;/code&gt; objects. That means doing something like this won't work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;MyStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;newProject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, use the second argument, &lt;code&gt;o&lt;/code&gt; above, which contains the un-proxied original state. Another gotcha is making sure not to return anything from the &lt;code&gt;update&lt;/code&gt; function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;After having used Pullstate, I will have a hard time not recommending it to all &lt;a href="https://ionicframework.com/react"&gt;Ionic React&lt;/a&gt; developers, and those using &lt;a href="https://capacitorjs.com/"&gt;Capacitor&lt;/a&gt; with other React UI libraries.&lt;/p&gt;

&lt;p&gt;I think Pullstate is a great middle ground between being simple for small projects, but clearly capable of scaling to much more complicated projects. For larger projects multiple stores can be created in parallel, for a sort of redux reducer-inspired organization.&lt;/p&gt;

&lt;p&gt;Pullstate also comes with some convenience helpers for &lt;a href="https://lostpebble.github.io/pullstate/docs/async-actions-introduction"&gt;async actions&lt;/a&gt; to cut down on async state boilerplate (such as handling success and failure states), though I have not used those extensively yet.&lt;/p&gt;

&lt;p&gt;Next on my list is exploring how this might work with something like &lt;a href="https://github.com/reduxjs/reselect"&gt;reselect&lt;/a&gt; for building reusable, memoized selectors.&lt;/p&gt;

&lt;p&gt;What do you think? Have you used Pullstate? Please share in the comments!&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>ionic</category>
    </item>
    <item>
      <title>HIPAA Compliant Mobile Apps With Ionic</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Tue, 18 Aug 2020 14:03:48 +0000</pubDate>
      <link>https://forem.com/ionic/hipaa-compliant-mobile-apps-with-ionic-2bf4</link>
      <guid>https://forem.com/ionic/hipaa-compliant-mobile-apps-with-ionic-2bf4</guid>
      <description>&lt;p&gt;HIPAA compliance for mobile is the responsibility of app development teams and their companies. While mobile technologies and platforms like Ionic provide UI and integration with Native SDKs, they do not handle user data or network security as it pertains to HIPAA compliance. Nor would any other mobile technology, it’s simply out of the purview of a mobile framework.&lt;/p&gt;

&lt;p&gt;However, what a platform like Ionic will provide, is the building blocks and APIs needed for teams to correctly implement user data storage and network security to follow HIPAA compliance guidelines and secure Protected Health Information (PHI)&lt;/p&gt;

&lt;p&gt;In this post we explore the APIs and techniques often used as part of a HIPAA compliant mobile experience, but discussion of broader HIPAA compliance concerns is out of scope for this blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  Storing Sensitive User Information
&lt;/h2&gt;

&lt;p&gt;When dealing with sensitive user information, the ideal scenario is to never persist it at all. However, that is not practical for a variety of performance and offline use cases.&lt;/p&gt;

&lt;p&gt;Thus, apps must find a way to store user data or sensitive user information, such as authentication tokens encrypted at rest using the full security capabilities of the mobile device.&lt;/p&gt;

&lt;p&gt;Consequently, this decision presents two more considerations: securing authentication while enabling biometric auth to enable auto login-in, and storing encrypted data at rest using managed encryption keys.&lt;/p&gt;

&lt;p&gt;To enable biometric authentication and the protection and encryption of a user session token, iOS and Android keychain/keystore APIs must be utilized. These APIs enable apps to store sensitive values in secure regions on the device and use powerful encryption that is tangled with the biometric hardware, meaning decryption can only happen with a valid biometric scan. Ultimately, this means data is encrypted at rest and cannot be bypassed on jailbroken devices.&lt;/p&gt;

&lt;p&gt;However, there are a number mistakes teams make implementing these complex APIs, and many are &lt;a href="https://ionicframework.com/blog/common-biometric-authentication-security-mistakes/"&gt;documented here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thankfully, teams do not have to implement these complex APIs and security flows themselves, as there are off-the-shelf solutions to storing sensitive user data, such as Ionic’s &lt;a href="https://ionicframework.com/enterprise/identity-vault"&gt;Identity Vault&lt;/a&gt; and &lt;a href="https://ionicframework.com/enterprise/offline-storage"&gt;Encrypted Storage&lt;/a&gt; solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Network Transport Security
&lt;/h2&gt;

&lt;p&gt;Apps will need to send data over the network, and this data may contain PHI. &lt;/p&gt;

&lt;p&gt;As a start, all network requests must use SSL (aka HTTPS). Ensure every endpoint is protected by SSL. Ensure your app does not embed resources such as images using http://. Also use APIs such as App Transport Security (ATS) to ensure SSL usage across the app.&lt;/p&gt;

&lt;p&gt;One other technique your app should strongly consider using is SSL pinning. SSL pinning essentially locks your app into one corresponding valid certificate for a network endpoint. This ensures no man-in-the-middle attack could occur which would result in  the compromising of sensitive data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protecting Screen Data
&lt;/h2&gt;

&lt;p&gt;When a user suspends an app, most mobile operating systems will show a snapshot of the last state of the app for app switchers and other OS experiences.&lt;/p&gt;

&lt;p&gt;To ensure that no sensitive information is leaked in one of these snapshots, your app should listen for app lifecycle events and obscure screen contents. This is typical of most apps in high-security contexts, such as banking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessing Sensitive APIs and Following ToS
&lt;/h2&gt;

&lt;p&gt;Many health apps need to access health data on a device. On iOS, this means HealthKit, on Android, this means Google Fit. &lt;/p&gt;

&lt;p&gt;It’s important to make sure any data accessed using these, and other APIs, adheres to your app’s HIPAA requirements.&lt;/p&gt;

&lt;p&gt;Additionally, Apple and Google have terms of service requirements for using their APIs. Your app must also follow those.&lt;/p&gt;

&lt;p&gt;This point might seem obvious but it’s critical that any access of APIs or sensors is intentional and follows all app store and compliance requirements. Many apps access more data and APIs than they will ever need, creating added security and compliance issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloud Considerations
&lt;/h2&gt;

&lt;p&gt;Of course, mobile technologies like Ionic focus only on the &lt;em&gt;frontend&lt;/em&gt; of an app, rather than the backend. Thus, HIPAA compliance for your app's backend is a separate concern and a massive part of the work in building a HIPAA compliant app.&lt;/p&gt;

&lt;p&gt;Likely your backend or infrastructure teams will take this on themselves but it's critical the mobile team works closely with the backend team to ensure no compliance violations occur.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hit the Ground Running with Ionic
&lt;/h2&gt;

&lt;p&gt;Ionic is a mobile development platform that many healthcare companies are using to build successful HIPAA compliant apps across iOS, Android, and the Web. Ionic offers a number of open source and commercial components focused on enabling developers with a web development background to be highly productive on mobile.&lt;/p&gt;

&lt;p&gt;As it pertains to this list of HIPAA compliance needs, Ionic offers some key drop-in security features that make it easy to adopt best practices and meet HIPAA compliance goals.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ionicframework.com/enterprise/identity-vault"&gt;Ionic Identity Vault&lt;/a&gt; brings biometric authentication, along with secure data storage and encryption, using security best practices on iOS and Android. Identity Vault manages using low-level security APIs such as Keychain on iOS and KeyStore on Android, ensuring that sensitive data such as authentication tokens, encryption keys, and sensitive user data are encrypted using the most secure hardware and software capabilities available on each operating system and device. With Identity Vault, apps can support user-expected features such as biometric login without fear of security issues.&lt;/p&gt;

&lt;p&gt;Ionic’s &lt;a href="https://ionicframework.com/enterprise/offline-storage"&gt;Encrypted SQLlite solution&lt;/a&gt; provides a high-performance data store with powerful, military-grade encryption support. When used with Identity Vault, encryption keys can be safely managed on device and only available when the actual user is present.&lt;/p&gt;

&lt;p&gt;Finally, Ionic’s &lt;a href="https://ionicframework.com/enterprise/auth-connect"&gt;Auth Connect&lt;/a&gt; solution provides a secure authentication flow for popular auth providers (Ping, Azure AD, and more).&lt;/p&gt;

&lt;h2&gt;
  
  
  Let Ionic Help Make your Mobile Health App Successful
&lt;/h2&gt;

&lt;p&gt;Ionic works with hundreds of enterprise teams building mission-critical, highly secure mobile apps, including many in the healthcare space.&lt;/p&gt;

&lt;p&gt;There’s a good chance we can help your team build a successful, highly secure, and compliant mobile health app.&lt;/p&gt;

&lt;p&gt;Interested? &lt;a href="https://ionicframework.com/demo"&gt;Get in touch&lt;/a&gt; to schedule a demo with an Ionic Solutions Architect.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>mobile</category>
      <category>security</category>
      <category>authentication</category>
    </item>
    <item>
      <title>Saying Goodbye to PhoneGap</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Tue, 11 Aug 2020 15:40:30 +0000</pubDate>
      <link>https://forem.com/ionic/saying-goodbye-to-phonegap-1gp4</link>
      <guid>https://forem.com/ionic/saying-goodbye-to-phonegap-1gp4</guid>
      <description>&lt;p&gt;Adobe just announced that they are &lt;a href="https://blog.phonegap.com/update-for-customers-using-phonegap-and-phonegap-build-cc701c77502c"&gt;shuttering PhoneGap, PhoneGap Build&lt;/a&gt;, and their (long non-existent) investment in Apache Cordova.&lt;/p&gt;

&lt;p&gt;As the pioneer of hybrid app development, &lt;em&gt;aka web developers building mobile apps&lt;/em&gt;, this is truly the end of an era.&lt;/p&gt;

&lt;p&gt;But it's hardly the end of the hybrid app development story. Companies like &lt;a href="https://ionicframework.com/"&gt;Ionic&lt;/a&gt; have been the leader in this space for a while, so this sunset feels predictable and, frankly, a long time coming.&lt;/p&gt;

&lt;p&gt;I wanted to take this opportunity to reflect on the hybrid app development market, thank the PhoneGap team for pioneering it, and wonder where it goes from here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Devs Rule the World
&lt;/h2&gt;

&lt;p&gt;The brilliant realization that the PhoneGap team had in the beginning was that Web Developers would want to use their existing skills, browser development workflows, and web dev teams to build mobile apps.&lt;/p&gt;

&lt;p&gt;Convincing the rest of the mobile market wasn't easy, however. PhoneGap faced intense backlash from the existing native app developer world. These developers went out of their way to trash PhoneGap and the apps that developers were creating on the platform, essentially classifying web developers building mobile apps as second-class. In some cases it felt like a full on war.&lt;/p&gt;

&lt;p&gt;Over time, PhoneGap would be proven right: web developers want to use their skills &lt;em&gt;everywhere&lt;/em&gt;, and few platforms are as large and as exciting as mobile. Web Developers never stopped honing their mobile skills and the hybrid app development ecosystem evolved to cater to them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adobe Passes the Torch
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ionicframework.com/"&gt;Ionic Framework&lt;/a&gt; was launched in 2013 right as the first era of hybrid app development was coming to an end. The iPhone 5 just came out, dramatically pushing the capabilities of the web platform and mobile web performance forward. Android 2.3 was quickly dying and modern Android was just making inroads.&lt;/p&gt;

&lt;p&gt;Ionic Framework had a simple pitch: web developers have proven they want to build mobile apps, but there was no official UI library for these apps, so developers struggled to get their UI experience on par with native. Ionic Framework was that library.&lt;/p&gt;

&lt;p&gt;Additionally, getting high performance from a web-based UI library was hard, so Ionic took the best practices for web performance and baked them into the UI library so web developers didn't have to worry about it.&lt;/p&gt;

&lt;p&gt;And it took off. Over the last 7 years Ionic apps built on Cordova grew to a &lt;a href="https://appfigures.com/top-sdks/development/apps"&gt;significant portion of the app stores&lt;/a&gt; with millions of apps created.&lt;/p&gt;

&lt;p&gt;Along the way, Adobe started taking a back seat and essentially passed the torch to Ionic years ago. Adobe hasn't been active in this space for many years now and Ionic has become the leader in cross-platform mobile app dev for web developers. Thus, the news of PhoneGap shuttering was hardly a surprise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Devs Want to Web Dev
&lt;/h2&gt;

&lt;p&gt;Over the years, the mobile market has changed quite a bit. New projects like React Native, Flutter, and NativeScript have challenged hybrid app development and have brought developers more options for building apps.&lt;/p&gt;

&lt;p&gt;But one thing that hasn't changed: web developers want to build web apps and run them &lt;em&gt;everywhere&lt;/em&gt;. They want to use their existing skills, browser-based development process, web libraries, and code to build mobile apps. This explained the rise of Cordova/PhoneGap in the first place, and the rise of Electron for desktop.&lt;/p&gt;

&lt;p&gt;Cordova (and the modern alternative &lt;a href="https://capacitorjs.com/"&gt;Capacitor&lt;/a&gt;) is still the only game in town for web developers that want to bring their web apps to mobile, and &lt;a href="https://ionicframework.com/"&gt;Ionic Framework&lt;/a&gt; is still the most popular UI library for them to do it. "Electron for Mobile," if you will.&lt;/p&gt;

&lt;p&gt;In contrast, React Native requires developers to build their UI from scratch, &lt;a href="https://capacitorjs.com/blog/native-react-apps-without-react-native"&gt;won't work with most React web UI projects&lt;/a&gt;, doesn't support standard CSS, and can't use most react web libraries (web dev w/ React is &lt;a href="https://npmcharts.com/compare/react-native,react-dom?interval=7"&gt;17x more popular than React Native&lt;/a&gt;). Flutter requires web devs to throw out their JavaScript investment and their web support is not viable for Progressive Web Apps.&lt;/p&gt;

&lt;p&gt;The "build once run anywhere" dream is alive and well in Capacitor and Cordova land, and the many thousands of apps being built on this platform each month as well as &lt;a href="https://ionicframework.com/customers"&gt;significant enterprise traction&lt;/a&gt; prove web devs still want to web dev.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;This space has seen enormous change over the last decade, and it's likely we'll see a lot more in the next. Progressive Web Apps are still nascent but there is growing frustration from developers all over the world about onerous app store requirements that limit a company's ability to reach and serve their users. Many teams are experimenting with &lt;a href="https://ionicframework.com/blog/forget-mobile-first-progressive-web-app-first-is-the-future/"&gt;Progressive Web App First Development&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Web Developers have honed their ability to build complex apps in the browser and are getting better and better at building high-performance experiences. Thus, the domination of React indicates not that React Native will be the winner for those devs building for mobile, but that &lt;a href="https://capacitorjs.com/blog/native-react-apps-without-react-native"&gt;React devs building React web apps for mobile&lt;/a&gt; is one of the most promising spaces to watch.&lt;/p&gt;

&lt;p&gt;Finally, cross-platform is clearly here to stay, and tools like Flutter prove a lot more developers outside of the web dev world want to build for multiple platforms at once. Will it become strange one day to build native apps for single platforms? I don't know, but we're going to find out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks Adobe
&lt;/h2&gt;

&lt;p&gt;With this news, memories are flooding back of our time working with the PhoneGap team, many of whom have become friends and advisors to us at Ionic. I still find myself dreaming of riding bikes around Amsterdam after PhoneGap Day and the good times we had.&lt;/p&gt;

&lt;p&gt;With that, thank you PhoneGap (and, by extension, Adobe) for pioneering this space and helping us at Ionic. Without you, we never would have been able to start this company and we never would have made such great friends.&lt;/p&gt;

&lt;p&gt;Farewell 👋&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>ionic</category>
    </item>
    <item>
      <title>Common Biometric Authentication Security Mistakes</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Tue, 11 Aug 2020 13:34:03 +0000</pubDate>
      <link>https://forem.com/ionic/common-biometric-authentication-security-mistakes-2bna</link>
      <guid>https://forem.com/ionic/common-biometric-authentication-security-mistakes-2bna</guid>
      <description>&lt;p&gt;Most apps utilizing authentication need to provide the user with ways to persist user sessions, or store sensitive values such as encryption keys, all while enabling automatic login using biometrics.&lt;/p&gt;

&lt;p&gt;There is one very common way that developers first try to implement this: show the fingerprint or face id prompt, and once the user passes it, load the token or value from local storage or a sqlite database and use it.&lt;/p&gt;

&lt;p&gt;Unfortunately, this is the approach that many apps and almost all of the community Cordova/Capacitor plugins take, and it’s &lt;strong&gt;not fully secure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s dig into some common mistakes implementing biometric auth and storing sensitive values, and then learn how proper biometric authentication and secure, encrypted value storage should be implemented.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistake #1: Just showing a biometric prompt
&lt;/h2&gt;

&lt;p&gt;The APIs for using biometric hardware on iOS and Android are easy to use at the surface level. Because of this, many developers simply show the biometric dialog (such as a fingerprint or face scan), wait for the success value, and then use that as proof of user presence.&lt;/p&gt;

&lt;p&gt;The problem with this is that biometric hardware can be bypassed especially when on a jailbroken device. That means a successful result doesn’t tell you that the real user is actually there. If bypassed, your app may happily load and use sensitive data meant for a different user.&lt;/p&gt;

&lt;p&gt;A proper biometric auth flow will protect sensitive data with the actual result of a biometric scan, making it impossible to fake it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistake #2: Not storing tokens and sensitive values encrypted at rest
&lt;/h2&gt;

&lt;p&gt;Many teams store JWT tokens or other sensitive values in unencrypted storage locations, such as Local Storage, an unencrypted SQLite database, or other locations.&lt;/p&gt;

&lt;p&gt;Unfortunately, this data can be accessible on jailbroken devices and through other possible exploits, meaning an attacker could find those sensitive values and steal user sessions, encryption keys, or more.&lt;/p&gt;

&lt;p&gt;Any sensitive user data or session information needs to be stored using strong encryption.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistake #3: Not using Biometric APIs for Keychain/etc.
&lt;/h2&gt;

&lt;p&gt;Teams using Keychain on iOS or Keystore on Android are a few steps ahead, but many are making another big mistake: not using Biometric configuration options for Keychain value storage, or not handling biometric enrollment or revocation so data protected for one user does not become exposed to another user.&lt;/p&gt;

&lt;p&gt;This leaves data exposed to exploits and jailbroken devices where the sensitive keychain data could be accessed without a biometric prompt being passed. &lt;/p&gt;

&lt;h2&gt;
  
  
  Solution: Use Ionic Identity Vault
&lt;/h2&gt;

&lt;p&gt;The low-level security APIs on iOS and Android are complex, but generally, the ability to associate actual biometric data with sensitive values in order to encrypt them in secure locations on the device is the gold standard for mobile security.&lt;/p&gt;

&lt;p&gt;That means full usage of the Keychain/KeyStore APIs on iOS/Android, processing biometric enrollment/unenrollment events, using encryption features for databases like SQLite, and making sure sensitive values are combined with biometric data to make them impossible to access without the actual user being present.&lt;/p&gt;

&lt;p&gt;Thankfully, teams don’t need to write the complex native code to implement this themselves,  as there is a solution to this problem for teams requiring the highest level of security for their apps: &lt;a href="https://ionicframework.com/enterprise/identity-vault"&gt;Ionic Identity Vault&lt;/a&gt;. Identity Vault is a drop-in identity and value storage solution providing advanced biometric APIs for iOS and Android, including deep integration with security APIs and encryption routines.&lt;/p&gt;

&lt;p&gt;Identity Vault manages the complexity of biometric authentication, user finger/face enrollment, device-level encryption at rest, and protecting sensitive data on screen.&lt;/p&gt;

&lt;p&gt;Additionally, Identity Vault was designed to work with other Ionic enterprise native solutions, including &lt;a href="https://ionicframework.com/enterprise/auth-connect"&gt;Auth Connect&lt;/a&gt; and our &lt;a href="https://ionicframework.com/enterprise/offline-storage"&gt;encrypted SQLite solution&lt;/a&gt; for secure online and offline apps. When used with these solutions, Identity Vault will correctly and securely manage authentication tokens and encryption keys, respectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started With Identity Vault Today
&lt;/h2&gt;

&lt;p&gt;Identity Vault is in use at hundreds of enterprise companies and fast growing startups.&lt;/p&gt;

&lt;p&gt;We would love to help your team create the most secure mobile app possible with Identity Vault. Interested? &lt;a href="https://ionicframework.com/enterprise/identity-vault#demo"&gt;Get a demo!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mobile</category>
      <category>security</category>
      <category>authentication</category>
      <category>oauth</category>
    </item>
    <item>
      <title>PhoneGap Build Shutting Down? Try Appflow!</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Mon, 10 Aug 2020 15:02:37 +0000</pubDate>
      <link>https://forem.com/ionic/phonegap-build-shutting-down-try-appflow-313a</link>
      <guid>https://forem.com/ionic/phonegap-build-shutting-down-try-appflow-313a</guid>
      <description>&lt;p&gt;Adobe just announced that &lt;a href="https://blog.phonegap.com/update-for-customers-using-phonegap-and-phonegap-build-cc701c77502c"&gt;PhoneGap and PhoneGap Build are shutting down&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For many teams relying on PhoneGap Build for cross-platform builds, this, along with the recent iOS 13 build issues, is a big setback. Fortunately, it doesn't have to be! There is a great alternative to get your apps working that is a nearly drop-in replacement with some awesome additional features: &lt;a href="https://useappflow.com/"&gt;Appflow&lt;/a&gt; from &lt;a href="https://ionic.io/"&gt;Ionic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Appflow is a Mobile CI/CD service (aka cloud build service) with native support for hybrid apps, since it’s built by the team behind &lt;a href="https://ionicframework.com/"&gt;Ionic Framework&lt;/a&gt; and &lt;a href="https://capacitorjs.com/"&gt;Capacitor&lt;/a&gt;. Appflow fully supports PhoneGap, Cordova, and Capacitor apps, and provides managed and secure build environments for iOS, Android, and web. Additionally, Appflow brings &lt;a href="https://ionicframework.com/docs/appflow/deploy/intro"&gt;remote app updating&lt;/a&gt; and direct &lt;a href="https://ionicframework.com/docs/appflow/destinations/intro"&gt;publishing to app stores&lt;/a&gt;, which are significant productivity features that go way beyond PhoneGap Build.&lt;/p&gt;

&lt;p&gt;Today, Appflow has thousands of customers and is powering mission-critical apps across the the Fortune 1000 and fast growing startups. Appflow is also being heavily invested in by the Ionic team (read about our &lt;a href="https://ionicframework.com/blog/announcing-our-6m-raise-and-the-road-ahead/"&gt;recent fundraise&lt;/a&gt;), and has a number of exciting features in the pipeline to make native, hybrid, and Progressive Web App development easier and faster (stay tuned!).&lt;/p&gt;

&lt;p&gt;We understand that Appflow's pricing model is different from PhoneGap Build. We're currently exploring some pricing and plan changes to better align the two, but for the time being, we are offering new customers one month free when they sign up. Use the coupon &lt;strong&gt;BUILDWITHUS&lt;/strong&gt; when signing up for one month free. Users should start with the Launch plan to explore the native build features. See &lt;a href="https://ionicframework.com/pricing/compare"&gt;Pricing&lt;/a&gt; for more info.&lt;/p&gt;

&lt;p&gt;To get started, explore the &lt;a href="https://ionicframework.com/docs/appflow/cookbook/phonegap-build-migration"&gt;detailed migration guide&lt;/a&gt; for those switching from PhoneGap Build. We’ve partnered with Adobe to make sure the process is as smooth as possible.&lt;/p&gt;

&lt;p&gt;And don't forget: use the coupon &lt;strong&gt;BUILDWITHUS&lt;/strong&gt; when signing up for one month free. Use the Launch plan or above to get access to the cloud app build features in Appflow.&lt;/p&gt;

&lt;p&gt;Does your team need help transitioning? Please &lt;a href="https://ionicframework.com/enterprise/contact"&gt;get in touch&lt;/a&gt;, we're standing by to help make this transition as painless as possible.&lt;/p&gt;

&lt;p&gt;Finally, we'd like to thank our friends at Adobe and PhoneGap for pioneering hybrid app development as we know it, and hosting some of the best conferences we've ever been to. The time is right for the Ionic team to carry the torch as the modern leader in cross-platform hybrid app development and we are confident we can help any and all teams impacted by this change. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>mobile</category>
      <category>ionic</category>
    </item>
    <item>
      <title>Appflow: not just another CI/CD Service</title>
      <dc:creator>Max Lynch</dc:creator>
      <pubDate>Fri, 10 Jul 2020 16:42:49 +0000</pubDate>
      <link>https://forem.com/ionic/appflow-not-just-another-ci-cd-service-4llh</link>
      <guid>https://forem.com/ionic/appflow-not-just-another-ci-cd-service-4llh</guid>
      <description>&lt;p&gt;Every production mobile app ultimately has a set of recurring tasks around integration, testing, deployment, and long term maintenance. These tasks often must be automated across a team of many developers and app projects. Building a process for these tasks can be incredibly time consuming and require specialized infrastructure experience, but is critical for the success of any serious app project.&lt;/p&gt;

&lt;p&gt;Thankfully, teams don’t need to build solutions to these problems themselves, as there are services out there that can help. One such service works directly with your Cordova or Capacitor app to help your team easily perform these tasks. That means consistent builds, deploys on every commit, pushing remote app updates in realtime, and automating app store deployment as part of your mobile CI/CD workflow.&lt;/p&gt;

&lt;p&gt;That service is &lt;a href="https://useappflow.com/"&gt;Appflow&lt;/a&gt;, and it’s &lt;a href="https://ionic.io/"&gt;Ionic&lt;/a&gt;’s official Mobile DevOps platform. Appflow automates the whole DevOps side of your mobile app project, and is used to power significant apps and development teams across AAA, Burger King/Popeyes, Shipt, and more.&lt;/p&gt;

&lt;p&gt;Let’s explore what a Mobile DevOps platform like Appflow is, what Appflow offers, how it differs from traditional CI/CD platforms, and how it’s being used today.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Mobile DevOps?
&lt;/h2&gt;

&lt;p&gt;Appflow is known as a Mobile DevOps platform.&lt;/p&gt;

&lt;p&gt;Mobile DevOps platforms, of which Appflow is one of the leaders, automate and simplify many continuous integration and delivery tasks, as well as other important mobile app deployment tasks. These platforms handle the heavy lifting so teams can focus on building their unique app, instead of reinventing the wheel.&lt;/p&gt;

&lt;p&gt;Those tasks may include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up consistent, repeatable mobile build environments so apps can be built on every commit using predictable dev tools and operating systems.&lt;/li&gt;
&lt;li&gt;Building app binaries and artifacts for iOS, Android, and Web&lt;/li&gt;
&lt;li&gt;Running tests and other scripts on every commit to ensure apps stay working&lt;/li&gt;
&lt;li&gt;Connecting to existing GitHub, Gitlab, Bitbucket, and other repos to perform builds on every commit&lt;/li&gt;
&lt;li&gt;Releasing working updates to users in realtime (for web updates), or to the app stores (for binary updates)&lt;/li&gt;
&lt;li&gt;Managing different versions of apps between testers, stakeholders, and production users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not every platform supports all of those features (Appflow does, as we’ll see below), but these are generally the tasks that a Capacitor or Cordova development team will need to perform.&lt;/p&gt;

&lt;p&gt;Beyond these tasks, DevOps is all about creating a culture of shipping often, involving stakeholders, and ensuring quality. All of which Mobile DevOps products can help your team embrace.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Appflow?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://useappflow.com/"&gt;Appflow&lt;/a&gt; is the official Mobile DevOps platform built by the Ionic team, focused on bringing powerful Mobile DevOps workflows to hybrid app developers across &lt;a href="https://capacitorjs.com/"&gt;Capacitor&lt;/a&gt; and Cordova whether or not they are using Ionic Framework.&lt;/p&gt;

&lt;p&gt;Appflow, first and foremost, is a managed mobile build environment. That means it provides consistent and frequently updated iOS, Android, and web build environments. The Appflow team does the hard work of keeping mobile build tools and operating systems up to date and patched for security issues, whether that means updating to the latest versions of Xcode or the Android SDK, or new versions of macOS and Linux, and a whole lot more.&lt;/p&gt;

&lt;p&gt;These builds are done in a highly secure environment, so teams can feel confident in offloading their mobile CI/CD process to Appflow, and on high performance hardware to make builds match the speed of development.&lt;/p&gt;

&lt;p&gt;Appflow also manages authentic, legal Mac build hardware for fully automating iOS builds in the cloud, which also benefits developers on Windows machines that wish to build iOS apps but can’t or don’t want to buy Mac hardware.&lt;/p&gt;

&lt;p&gt;On top of this environment, Appflow provides some pretty transformative features for hybrid app developers. Namely, the ability to remotely update an app without needing to re-submit to app stores (in a way that is App Store ToS friendly!), as well as publish app binaries directly to the Apple App Store and Google Play Store.&lt;/p&gt;

&lt;p&gt;And Appflow can automate that whole process so it triggers on each commit, as well as enable powerful version splitting so testers, stakeholders, and customers can run on different versions of an app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can’t I do this with Circle CI, GitHub Actions, or Azure DevOps?
&lt;/h2&gt;

&lt;p&gt;In the CI/CD space, there are generic build services like Circle CI or GitHub Actions, and there are specialized services like Appflow.&lt;/p&gt;

&lt;p&gt;The biggest difference between the services is that Circle CI or GitHub Actions merely provide build servers, a way to trigger builds, and hooks for sending those builds elsewhere. They do not provide the tools or pipeline for mobile-specific builds, they do not handle the deployment of your app, and they certainly don’t manage build environments for you.&lt;/p&gt;

&lt;p&gt;Here’s a visualization of the differences between the two approaches:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.ionicframework.com/wp-content/uploads/2020/07/graphic.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fSPz0pNY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.ionicframework.com/wp-content/uploads/2020/07/graphic-925x1024.png" alt="Appflow vs generic CI/CD platform" class="aligncenter size-large wp-image-3348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In theory, teams could build their own Appflow-style pipeline on another generic CI/CD platform like Circle CI or GitHub Actions, but that would require teams orchestrate and keep up to date a very complex chain of tools, operating systems, build environments, app store submission features, remote app deployment, and more. This is guaranteed to take a full team of engineers with a different skillset than the app dev team to build and manage, especially as new mobile and desktop operating systems are released each year.&lt;/p&gt;

&lt;p&gt;It’s simply not feasible for the vast majority of teams to take this on in addition to building their apps.&lt;/p&gt;

&lt;p&gt;This is why a specialized build service like Appflow stands out in the CI/CD and DevOps space. Beyond simply being a build service, Appflow is a managed mobile build environment that is fully managed by the mobile experts here at Ionic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not both?
&lt;/h2&gt;

&lt;p&gt;Generic CI/CD tools, with their focus on simply triggering builds, are not a direct replacement for Appflow. That means the two can easily be used alongside each other.&lt;/p&gt;

&lt;p&gt;In this scenario, a team might have their generic CI/CD tool trigger builds and push code to Appflow, while Appflow manages the hard work of performing mobile builds on managed mobile development infrastructure, while also handling the last mile app update and app store publishing.&lt;/p&gt;

&lt;p&gt;This works so well that around 68% of Appflow customers are using Appflow alongside a general purpose CI/CD tool, according to data from the &lt;a href="https://ionicframework.com/survey/2020"&gt;2020 Ionic Developer Survey&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This delivers the best of both worlds: You get to continue using your CI/CD tool of choice - or whatever your company has standardized on - while leaving the highly specialized, mobile specific build and publishing requirements to Appflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who’s using Appflow Today?
&lt;/h2&gt;

&lt;p&gt;Appflow has thousands of customers across a diverse range of companies. Appflow powers workflows in fast growing startups, established SMBs, and the largest enterprise companies in the world.&lt;/p&gt;

&lt;p&gt;Some of the customers using Appflow as a cornerstone of their mobile app development strategy include RBI (Burger King/Popeyes), AAA, and Shipt. Another customer, Napa Group, had this to say about Appflow:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“One of the huge advantages of using Ionic Appflow was to have these different Channels, which are essentially environments to us. We can push code to our Development environment and have QA test it; then we can move it to Staging and do a smoke test; then, with a single button click [using Ionic Deploy] all our code is live to our users. The amount of risk goes down exponentially compared to deploying the app on the app store, waiting for it to get reviewed, realizing there’s a bug and taking 2 or 3 more days before you can get a fix uploaded. That deployment speed is a huge asset for us.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;See the full &lt;a href="https://ionicframework.com/resources/case-studies/napa-group-llc"&gt;Napa Group Case Study&lt;/a&gt; for more details on their use of Appflow.&lt;/p&gt;

&lt;p&gt;The CI/CD and DevOps market is massive and growing quickly. We believe that every serious app development team will be utilizing CI/CD within the next few years, but most will struggle with sophisticated mobile CI/CD pipelines given their much more complex nature and dependency on a different engineering skillset than app dev teams traditionally have access to.&lt;/p&gt;

&lt;p&gt;Thus, teams are choosing Appflow today because they are not able to find what they need from generic CI/CD services like Circle CI, Travis, Azure DevOps, or GitHub Actions. They need reliable build environments and features tailored to hybrid app development. Appflow stands out as the leader in Mobile DevOps and we’re thrilled to see adoption growing quickly as it addresses this huge unmet need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Getting started with Appflow is easy. Visit &lt;a href="https://useappflow.com/"&gt;useappflow.com&lt;/a&gt;, click Try it Free, create or use your existing Ionic account, and jump into the &lt;a href="https://ionicframework.com/docs/appflow"&gt;Documentation&lt;/a&gt; to see how to connect your app and start pushing commits to Appflow.&lt;/p&gt;

&lt;p&gt;Or, if you're interested in exploring Appflow for your team, book a free &lt;a href="https://ionicframework.com/enterprise/strategy-session"&gt;strategy session&lt;/a&gt; with an app architect at Ionic. We help thousands of mobile teams move faster, and we'd love to help yours, too!&lt;/p&gt;

&lt;p&gt;Appflow is improving every day. Stay tuned for some really exciting new features coming to Appflow users in the coming months!&lt;/p&gt;

</description>
      <category>appflow</category>
      <category>capacitor</category>
      <category>devops</category>
      <category>mobile</category>
    </item>
  </channel>
</rss>
