At Ionic, we are big fans of TypeScript and use it in several of our important projects, including Ionic Framework, Stencil, Studio, and AppFlow. We find TypeScript beneficial for a number of reasons, but mostly because it helps us scale our large (and fairly complex) codebases in many areas, including:

  • Catching bugs before build time through static type checking
  • Providing code completion and refactoring support in many of our favorite editors, like VS Code, WebStorm, and even Vim
  • Allowing us to use modern language features of JavaScript before they are available in all browsers

We think TypeScript is great, and we think many of our Ionic Angular developers would agree. We have also found TypeScript to be beneficial outside of Angular as well. In fact, we use it in our own AppFlow dashboard, which is a large React app.

Over the past couple of years, TypeScript has started to gain momentum in the React world and, now, has official support in create-react-app. So, we thought it would be helpful to share a little tutorial on how to kick off a new React project using TypeScript.

Using Create-React-App

Create-react-app is the CLI for React projects. While not as encompassing as the Angular CLI, it still does a great job at creating new apps (hence its name).

Install the latest Create-React-App through npm:

npm install -g create-react-app

Now, start a new project by running create-react-app and specify your project name:

create-react-app reacttypescript
cd reacttypescript

This will scaffold out a new React project. Notice, we have not specified that this is a TypeScript project. It will use standard JavaScript with the Babel transpiler by default, but we will change that soon.

Next, we will install TypeScript and some typings in our project:

npm i typescript @types/react @types/react-dom @types/node @types/jest

The typing files provide static type checking and code completion for npm packages that aren’t written in TypeScript. Install any additional ones for other third-party libraries you will be using.

The magic of enabling TypeScript comes from renaming all the js files in the project with a tsx extension (if the file contains JSX), or a ts extension (if it does not). Go ahead and rename App.js to App.tsx, and start up the development server.

npm run start

And, just like that, your React project is running in TypeScript! When you run the start task, behind the scenes react-scripts will detect that the project has TypeScript and automatically run a TypeScript build, no need to set up one in a Webpack config.

Notice also that you now have a tsconfig.json file as well. This file was created the first time the start task is run in a TypeScript project. Feel free to customize the settings in here to fit your needs.

React Components in TypeScript

Next, let’s create a new component in TypeScript and consume it from our App to see some of the benefits we now receive.

Create a new file named SayHello.tsx and paste in the following code:

import * as React from 'react';

interface SayHelloProps {
  name: string;
  onGetNewName: () => void;
}

interface SayHelloState {
  count: number;
}

export default class SayHello extends React.Component<SayHelloProps,SayHelloState> {
  constructor(props: SayHelloProps) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    const { onGetNewName, name } = this.props;
    const { count } = this.state;
    return (
      <div>
        <p>Hello {name}!</p>{' '}
        <button onClick={() => onGetNewName()}>Enter new name</button>
        <p>You clicked {count} times</p>
        <button onClick={() => this.setState({ count: count + 1 })}>
          Click
        </button>
      </div>
    );
  }
}

While this example is a bit contrived, it does highlight a major benefit of TypeScript, which is statically typing our components by specifying interfaces for the props and state objects. The SayHelloProps and SayHelloState interfaces specify the shape of the props and state objects, which are then passed in as generic arguments to the Component class.

Now that our component is statically typed, it is no longer possible to accidentally mistype a name of one of our props or state members, nor can you try to assign it a value that does not match the member’s type.

What’s great about Typescript is that you can catch these errors right in your code editor and also during build time, as seen below.

Wrapping Up

TypeScript helps teams scale their JavaScript projects by providing modern language features, static type checking, and tooling. With the official support of TypeScript in create-react-app, I expect more React users will discover how great this language is and how it can help them with their development.

You might be wondering why a post about React on the Ionic blog? Well, in case you haven’t heard, Ionic 4.0 was built from the ground up to work with any framework, and we have some exciting updates about official support for React coming very soon.

Expect to see more React content coming from us in the future. In the meantime, check out a sample Ionic React app to see the alpha in action.

Want to see more of the benefits of using TypeScript in React? Hit us up in the comments section below or on Twitter with your questions and feedback.

Read more

Today we’re shipping Bootstrap v4.3.1 and v3.4.1 to patch an XSS vulnerability, CVE-2019-8331. Also included in v4.3.1 is a small fix to some RFS (responsive font sizes) mixins that were added in v4.3.0.

Earlier this week a developer reported an XSS issue similar to the data-target vulnerability that was fixed in v4.1.2 and v3.4.0: the data-template attribute for our tooltip and popover plugins lacked proper XSS sanitization of the HTML that can be passed into the attribute’s value.

To resolve the issue, we’ve implemented a new JavaScript sanitizer to only allow whitelisted HTML elements in data attribute. You may modify our sanitization implementation to customize the HTML element whitelist, totally disable the sanitization, or pass your own sanitize function (useful if you use your own library). However, for added protection, there is no way to modify the sanitization via data attributes—you must modify these plugin options via the JavaScript API.

Those who have modified the default templates, please read the new v4.3 sanitizer docs or the new v3.4 sanitizer docs.

In light of this vulnerability, we’re also auditing our security reporting workflows to ensure they’re up to date. This will include steps like adding a SECURITY.md file to our repository and ensuring our private channels and processes are up to date and documented with the team.

Thank you to poiu for reporting the vulnerability to the Bootstrap Drupal project and Mark Carver from the Bootstrap Drupal project for responsibly disclosing the issue to us. Also a massive thank you to @Johann-S, @Xhmikosr, and @bardiharborow on our team for the fast turnaround on today’s releases.

<3,
@mdo & team

Read more

Bootstrap v4.3 has landed with over 120 combined closed issues and merged pull requests. This release brings improvements to our utilities, some prep work for moving on to v5’s development, and the standard bug fixes and documentation updates.

During our last release, we shared a small preview of where we’re taking the project next. That’s getting clearer in the coming weeks as our attention turns towards embracing Hugo for ultra fast docs development, removing jQuery in favor of regular JavaScript, and addressing our growing code base.

Keep reading for v4.3 highlights, and see you soon with more details on v5!

Highlights

We’ve added some new utilities and deprecated some unused code. Here are the key changes in v4.3, broken down by new, improved, fixed, and deprecated.

  • New: Added .stretched-link utility to make any anchor the size of it’s nearest position: relative parent, perfect for entirely clickable cards!
  • New: Added .text-break utility for applying word-break: break-word
  • New: Added .rounded-sm and .rounded-lg for small and large border-radius.
  • New: Added .modal-dialog-scrollable modifier class for scrolling content within a modal.
  • New: Added responsive .list-group-horizontal modifier classes for displaying list groups as a horizontal row.
  • Improved: Reduced our compiled CSS by using null for variables that by default inherit their values from other elements (e.g., $headings-color was inherit and is now null until you modifier it in your custom CSS).
  • Improved: Badge focus styles now match their background-color like our buttons.
  • Fixed: Silenced bad selectors in our JS plugins for the href HTML attribute to avoid JavaScript errors. Please try to use valid selectors or the data-target HTML attribute/target option where available.
  • Fixed: Reverted v4.2.1’s change to the breakpoint and grid container Sass maps that blocked folks from upgrading when modifying those default variables.
  • Fixed: Restored white-space: nowrap to .dropdown-toggle (before v4.2.1 it was on all .btns) so carets don’t wrap to new lines.
  • Deprecated: img-retina, invisible, float, and size mixins are now deprecated and will be removed in v5.

Checkout the full v4.3.0 ship list and GitHub project for the full details.

Head to to the v4.3.x docs to see the latest in action. The full release has been published to npm and will soon appear on the Bootstrap CDN and Rubygems.

Introducing responsive font sizes

Responsive font-sizes

Our biggest new addition to Bootstrap in v4.3 is responsive font sizes, a new project in the Bootstrap GitHub org to automate calculate an appropriate font-size based on the dimensions of a visitor’s device or browser viewport. Here’s how it works:

  • All font-size properties have been switched to the @include font-size() mixin. Our Stylelint configuration now prevents the usage of font-size property.

  • Disabled by default, you can opt into this new behavior by toggling the $enable-responsive-font-sizes boolean variable.

  • font-sizes are entirely configurable via Sass. Be sure to read the docs for how to modify the scales, variables, and more.

While responsive font-sizes are disabled by default, we’ve enabled them in the custom CSS that powers our docs starting with v4.3. Please share feedback with us via GitHub issues or on Twitter. We’ve added some light guidance to our Typography docs to explain the feature. You can also learn more by reading the rfs project documentation.

Open Collective

Last December we launched our Open Collective page with our v3.4 release to help support the maintainers contributing to Bootstrap. The team has been very excited about this as a way to be transparent about maintainer costs (both time and money), as well as recognition of efforts.

Branches, Hugo, and jQuery

Right after shipping v4.3, we’ll be tackling a few key changes on our road to active v5 development. These are larger changes to how we maintain and develop Bootstrap and are considered foundational for v5.

  • Improving our branches for development. master will become our new v3-dev branch. v4-dev will stay as-is, but we’ll cut a new master branch from there to develop v5.

  • We’ve moving to Hugo! Jekyll has been great, but it’s starting to slow us down in local development. We’ll be making changes to our dependencies to support this move, and there’s already a pull request in progress and near completion for the change. Follow along to see what’s changing.

  • We’re dropping jQuery for regular JavaScript. The cat is out of the bag—we’re dropping our largest client-side dependency for regular JavaScript. Similar to the Hugo move, we’ve been working on this for a long time and have a pull request in progress and near completion.

We’ll have even more to share soon around v5’s plans after we tackle these bigger items. In the meantime, keep the feedback coming on GitHub and Twitter!

<3,
@mdo & team

Read more

Navigating the Change with Ionic 4 and Angular Router

This is a guest post from Simon Grimm, Ionic Developer Expert and educator at the Ionic Academy. Simon also writes about Ionic frequently on his blog Devdactic.

In this tutorial we will look at the new navigation system inside Ionic Framework 4.0 to learn how to use the powerful CLI, to understand how your Ionic 3 logic can be converted to v4, and, finally, the best way to protect pages inside your app if you plan to use an authentication system at any point.

I am Number 4

There is so much to talk about if we want to cover all the Ionic 4 changes, but for today let’s just focus on one of the key aspects of your app: Navigation!

With Ionic 4, your app is using Angular, which already comes with some new additions itself. But now Ionic is also using the standard Angular Router in the background. This means, instead of pushing and popping around inside your app, we have to define paths that are aligned with our pages.

If you are new to this concept, it might look a little scary and you may think, “Why so much code, everything was so easy before…,” but trust me, by the end of this post, you’ll love the new routing and you’ll be ready to migrate your Ionic 3 apps to the new version.

For now, let’s start with a blank Ionic 4 app so we can implement some navigation concepts. Go ahead and run:

npm install -g ionic@latest
ionic start goFourIt blank 

This will create a new project which you can directly run with ionic serve once you are inside that folder. It should bring up a blank app in your browser with just one page.

The Entry Point of Your App

When you inspect the folders of your app, you’ll find one HomePage at the src/app/home path. This is the page you see on screen (compare it’s HTML with what you see if you don’t trust me), but how is it actually loaded?

To understand this we need to open our app/app-routing.module.ts in which we will find:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
 { path: '', redirectTo: 'home', pathMatch: 'full' },
 { path: 'home', loadChildren: './home/home.module#HomePageModule' },
];

@NgModule({
 imports: [RouterModule.forRoot(routes)],
 exports: [RouterModule]
})
export class AppRoutingModule { }

This is the first place for routing information in our app and the place where we can add more information about how our app works. Right now, we have two routes defined inside the array.

The first, is actually a simple redirect that will change the empty path ‘’ to the ‘home’ path, so it’s like going to google.com/ and being redirected to google.com/home.

Inside the definition for the home path we can now spot the loadChildren key in which we supply a path to the module file of our home page. This module file holds some information and imports for the page, but you can think of it as the page that gets displayed.

Ok, cool, we now have a router and are loading a page through a path, so how is this connected with actual HTML or the index page of the app?

If you happen to inspect your index.html the only thing you’ll find is:

<body>
 <app-root></app-root>
</body>

The only thing we display is an app-root, which is still not very clear. This app root is replaced by the first real HTML of our app, which is always inside the app/app.component.html:

<ion-app>
 <ion-router-outlet></ion-router-outlet>
</ion-app>

This is the key to understanding how the routing works: The Angular Router will replace router outlets with the resolved information for a path.

This means inside the body, at the top level, we have this special Ionic router outlet (which is the standard Angular outlet plus some animation extras) wrapped inside a tag for the Ionic app itself. Once we navigate to a certain path, the router will look for a match inside the routes we defined, and display the page inside the right outlet.

We needed this short detour to get a solid understanding about why the things we’ve done work as they do. Now, you are hopefully ready to navigate the change a bit better.

Adding New Pages with the CLI

Because a single page is not yet an app, we need more pages! To do so, you can use the Ionic CLI, which provides a wrapper for the Angular CLI. Right now, we could add 2 additional pages like this:

ionic g page pages/login
ionic g page pages/dashboard
ionic g page pages/details

This command tells the CLI to generate (g) a new page at the path pages/login, pages/dashboard and pages/details. It doesn’t matter that the folder ‘pages’ does not yet exist, the CLI will automatically create them for you.

There’s a whole lot more you can do with the CLI, just take a look at the documentation.

For now, let’s get back to our main goal of implementing navigation inside our app.

After creating pages with the CLI your app-routing.module.ts will automatically be changed, which may or may not help you in some cases. Right now, it also contains routing information for the three new pages we added with the according path of their module.

Changing Your Entry & Navigating (a.k.a Push & Pop)

One thing I often do with my apps is change the initial page to be a different component. To change this, we can simply remove the routing information for the home page, delete its folder, and change the redirect to point to the login page we generated earlier.

Once a user is logged in, the app should then display our dashboard page. The routing for this is fine, so far, and we can leave it like it is.

For the detail page we generated, we do want one addition: URL parameters. Say that you want to pass data from one page to another. To do this, we’d use URL parameters and specify a dynamic slug in the path. For this routing setup, we’ll add :myid.

Your routing should now look like this inside your app-routing.module.ts:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
 { path: '', redirectTo: 'login', pathMatch: 'full' },
 { path: 'login', loadChildren: './pages/login/login.module#LoginPageModule' },
 { path: 'dashboard', loadChildren: './pages/dashboard/dashboard.module#DashboardPageModule' },
 { path: 'details/:myid', loadChildren: './pages/details/details.module#DetailsPageModule' }
];

@NgModule({
 imports: [RouterModule.forRoot(routes)],
 exports: [RouterModule]
})
export class AppRoutingModule { }

With previous Ionic versions you could also supply complete objects with a lot of information to another page, but with the new version this has changed. By using the URL routing, you can (and should) only pass something like an objects ID (to be used in a HTTP request) to the following page.

In order to get the values you need on that page later, simply use a service that holds your information or makes a HTTP request and returns the right info for a given key at any time.

All routing logic is officially in place, so now we only need to add a few buttons to our app that allow us to move around. Let’s start by adding a first button to our pages/login/login.page.html:

<ion-header>
 <ion-toolbar color="primary">
   <ion-title>Login</ion-title>
 </ion-toolbar>
</ion-header>

<ion-content padding>
 <ion-button expand="block" routerLink="/dashboard" routerDirection="root">
   Login
 </ion-button>
</ion-content>

We add a block button which has two important properties:
routerLink: The link/path that should be opened
routerDirection: Determines the animation that takes place when the page changes

After a login, you most certainly want to ditch your initial page and start again with the inside area as a new starting point. In that case, we can use the direction “root,” which looks like replacing the whole view.

If you want to animate forward or backward, you would use forward/back instead. This is what we can add now, because we are already able to move from login to our dashboard. So, let’s add the next two more buttons to the pages/dashboard/dashboard.page.html:

<ion-header>
 <ion-toolbar color="primary">
   <ion-title>Dashboard</ion-title>
 </ion-toolbar>
</ion-header>

<ion-content padding>
 <ion-button expand="block" routerLink="/details/42" routerDirection="forward">
   Details
 </ion-button>

 <ion-button expand="block" routerLink="/" routerDirection="root">
   Logout
 </ion-button>
</ion-content>

This is the same procedure as before—both have the link, but the first button will bring us deeper into our app by going to the details page and using “42” as the ID.

The second button brings us back to the previous login page again by animating a complete exchange of pages.

You can see the difference of the animations below:

Of course, you can also dynamically add the ID for the details page or construct the link like this if you have a variable foo inside your class:

<ion-button expand="block" [routerLink]="['/details/', foo]" routerDirection="forward">

To wrap things up we need to somehow get the value we passed inside our details page, plus your users also need a way to go back from that page to the dashboard.

First things first, getting the value of the path is super easy. We can inject the ActivatedRoute and grab the value inside our pages/details/details.page.ts like this:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
 selector: 'app-details',
 templateUrl: './details.page.html',
 styleUrls: ['./details.page.scss'],
})
export class DetailsPage implements OnInit {

 myId = null;
  constructor(private activatedRoute: ActivatedRoute) { }

 ngOnInit() {
   this.myId = this.activatedRoute.snapshot.paramMap.get('myid');
 }

}

By doing this, we can get the value, which is part of the paramMapof the current route. Now that we have stored the value, we can also show it inside the current view, plus add a button to the top bar that allows the user to navigate back.

With previous Ionic versions that back button was automatically added. Meaning, the button was there even if we didn’t want it and it was difficult to customize. But with the release of Ionic 4.0, we can control this by adding it ourselves. At the same time, we can also define a defaultHref. This way, if we load our app on that specific page and have no app history, we can navigate back and still have our app function.

The markup for our pages/details/details.page.html looks now like this:

<ion-header>
 <ion-toolbar color="primary">
   <ion-buttons slot="start">
     <ion-back-button defaultHref="/dashboard"></ion-back-button>
   </ion-buttons>
   <ion-title>Details</ion-title>
 </ion-toolbar>
</ion-header>

<ion-content padding>
 My ID is: {{ myId }}
</ion-content>

As you can see, this back-button will now always bring us back to the dashboard, even if we don’t have any history at that point.

By now, the whole navigation setup in our app works pretty flawlessly, but what if we wanted to restrict some routes to only authenticated user? Let’s go ahead and add this.

Protecting Pages with Guards

Many of us often need a way to prevent users from accessing certain pages in our app. This might not be super obvious when only focused on mobile apps, but think about a URL to a website: Your path is exactly this, and some users should simply not be allowed to visit that page if they are not authenticated.

When you deploy your Ionic app as a website, all URLs, right now, could be directly accessed by a user. But here’s an easy way to change it:

We can create something called guard that checks a condition and returns true/false, which allows users to access that page or not. You can generate a guard inside your project with the Ionic CLI:

ionic g guard guards/auth

This generates a new file with the standard guard structure of Angular. Let’s edit guards/auth.guard.ts and change it’s content to:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';

@Injectable({
 providedIn: 'root'
})
export class AuthGuard implements CanActivate {
 canActivate(
   next: ActivatedRouteSnapshot,
   state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

   let userAuthenticated = false; // Get the current authentication state from a Service!

   if (userAuthenticated) {
     return true;
   } else {
     return false;
   }
 }
}

The guard only has the canActivate() method in which you return a boolean if the page can be accessed. In this code, we simply return false, but a real guard would make an API call or check a token value.

By default this guard is not yet enabled, but now the circle closes as we come back to our initial app routing. So, open the app-routing.module.ts once again and change it to:

import { AuthGuard } from './guards/auth.guard';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

const routes: Routes = [
 { path: '', redirectTo: 'login', pathMatch: 'full' },
 { path: 'login', loadChildren: './pages/login/login.module#LoginPageModule' },
 { path: 'dashboard', loadChildren: './pages/dashboard/dashboard.module#DashboardPageModule' },
 {
   path: 'details/:myid',
   loadChildren: './pages/details/details.module#DetailsPageModule',
   canActivate: [AuthGuard]
 }
];

@NgModule({
 imports: [RouterModule.forRoot(routes)],
 exports: [RouterModule]
})
export class AppRoutingModule { }

You can add an array of these guards to your pages and check for different conditions, but the idea is the same: Can this route be activated by this user?

Because we set it to false without any further checks, right now we could not navigate from the dashboard to the details page.

There’s also more information on guards and resolver functions inside the Ionic Academy, so check it out here!

Where to Go From Here?

We’ve only touched on a few basic elements of the (new) Angular routing concepts that are now applied in Ionic 4, but I hope it was helpful. Now that you’ve walked through this process, this concept should be a lot easier to understand and manage given that your navigation is not scrambled across various pages inside your app.

Also, securing your app or resolving additional data before entering a page becomes a lot easier with the direct paths and the use of child routing groups.

If you’re interested in the concept of routing, or would like to see more explanations around features like the Tabs, Side Menu, or child routes and modals, consider becoming an Ionic Academy member, today!

When you join, you’ll gain access to countless resources that will help you learn everything Ionic, from in-depth training resources to video courses, plus support from an incredibly helpful community.

Until next time, happy coding!

Read more

Getting ready to kick off your next mobile application project and not sure whether to build a native mobile app or a Progressive Web App? This guide is for you!

At Ionic, we are fans of both traditional mobile apps (the kind you download from the app stores and install on your device) and Progressive Web Apps (PWAs). And, we have the tools you need to build either, or both, types of apps. To help you decide which is better for your next project, we’re going to take a practical look at some of the top considerations for each one. We’ll break it down into four categories: Device reach, app-like look and feel, device integrations, and distribution. Let’s dive in!

Device Reach

The first factor you want to think about when considering a PWA is device reach. Some important questions might be: What devices does your app need to run on? Is it meant for the mobile user, the desktop user, or both? Do the web browsers you’re targeting provide support for PWAs?

Since the theme of this post is mobile development, it’s safe to say you’re likely thinking of targeting mobile devices, which, today, mainly means iOS and Android. But do you also need to reach users who are on their desktop computers as well? With user preferences evolving to expect a company’s digital experiences to be available on any and all devices—Chances are, you do.

If you were to go native, it could mean that up to three apps need to be built, each with their own codebase.

Alternatively, PWAs are built with web technology and the web has the furthest reach of any other platform, running just about everywhere. Meaning, with a PWA, an app can be built once with the same codebase and is able to reach all your target devices.

However, there are still a few more questions to consider when thinking about PWAs and device reach, such as browser support. Do the web browsers you need to support run PWAs? Most browsers today support the majority of PWA features, but what if we have a browser that does not?

And, even if a browser isn’t supported, is it okay if a user has a downgraded experience in case a particular feature is not available to them? Additionally, is it important that all users have the same experience, or is it better to provide an optimal experience to those users who have the latest supported browsers, but still provide a graceful fallback to those that do not?

If you opt for a PWA, using progressive enhancement techniques can help provide optimal experiences for all users.

However, if a particular device feature, or the exact same UX, is something that’s required to be successful, but not all user browsers support it yet, then building a native app might be the way to go.

App-Like

Usually, when people say “app-like,” it often comes down to the following qualities:

  • Native look-and-feel: Does your app look and behave like it should on the device it is being used? Can users easily navigate on the app, with natural movements, to find what they are looking for?
  • Speed & Performance: Does your app load quickly and feel responsive when a user interacts with it? Does it launch quickly?
  • Offline Support: Does your app still have a useable experience (even if limited) when there is little to no network connection?
  • Installable: Can users launch your app from an icon on their home screen?
  • Native Functionality: Can your app do things often found in native apps, like receive push notifications or access device hardware like the camera and sensors?

Just a few years ago, a mobile website was not a viable option as a replacement for native mobile apps. A mobile site just didn’t “feel right” running inside a browser, even if it did mimic the UI of a native device.

Progressive Web Apps, however, fix the shortcomings of mobile websites by addressing all of the above app-like concerns. Additionally, a mobile UI framework, like Ionic, can give a mobile app the look and feel it needs, while recent web standards give PWAs the offline support and device integrations necessary to make it feel like an app. Once installed, users will probably never notice (or care), if the app is a PWA or downloaded from a store.

Device Integration

Next among considerations between choosing a native app or PWA is what type of device integration your app needs.

Devices are equipped with various sensors and capabilities that native apps, naturally, have full access to. However, this doesn’t necessarily mean you need a native app to access these features. However, what does matter is which device features are important to your app, and what level of control is needed when working with these features.

Fortunately, the web platform provides web-based APIs to access many of these features. There are APIs to access device hardware like cameras, GPS, accelerometers, biometric sensors, and more.

Despite this, the web APIs available might not provide the specific access you need, or a particular feature may not be available, yet, in all browsers. If this is the case, it might be a legitimate reason to choose a native app over a PWA.

When it comes to device integration, you must evaluate what type of accessibility and functionality is needed before choosing which approach is best. For a majority of apps, PWAs will be a good option, but for those that just need access to certain features, then going native will be required.

The web platform is constantly improving, though, and more device APIs are popping up all the time, so it is likely that something that is not currently available might be coming soon.

Distribution

The last question to consider when choosing a development approach for a mobile app is: How will the app be distributed and published?

PWAs enjoy the same distribution story as normal websites. Once pushed to a server, PWAs are available to everyone. Here are some advantages of PWA distribution:

  • Updates are quick with no need to go through app store approval processes
  • The content of a PWA can still be indexed by search engines, meaning an app is still searchable and linkable
  • If you are building apps for an enterprise, and it is internal only, then distributing the app as a PWA might be a lot simpler than going through an enterprise app store

There are still some benefits to the traditional app store model. Here are a few:

  • Apps in the store can be more easily monetized (though that money is split with the store in hefty chunks)
  • The app stores can promote your app. And, apps lucky enough to be featured can have a huge boon to their downloads
  • The app stores provide metrics and error reporting for apps, automatically
  • The app stores provide the bandwidth and infrastructure for your app downloads
  • Native apps get full hardware API access (as discussed above)

There might be some good reasons to put your app in the app stores. However, this doesn’t necessarily mean a PWA still is not a good choice, as a relatively new trend is starting where a few stores are accepting submissions from PWAs!

For example, Microsoft has let developers submit PWAs to its store for some time now. Some advantages gained using this method are discoverability in the store, monetization through the store (like in-app purchases), and access to device hardware APIs. The best part is, PWAs are still distributed as a normal website, and the store basically just links to the PWA’s site, so you still enjoy the same distribution benefits as a normal PWA.

APIs have surfaced in the latest Chrome update that shows Google is also preparing for PWAs to be a first-class citizens in its store as well. While there is no official documentation on this (as of when this post was written), expect to hear some more about these exciting developments from us soon.

Why Not Both?

So, after reviewing all these considerations you may have discovered that having a native app in the stores is needed. But, you may also still find PWAs intriguing because they have their own merits and are worth pursuing for a number of reasons. If you feel this way, that’s ok! Because, my next question is: Why not have both a PWA and native app with the same codebase?

This is where Ionic comes in. Traditionally, Ionic has been used to build mobile apps with web technology by utilizing the hybrid capability of Cordova to package those web assets into native packages that you can distribute directly to the app stores. These apps still get native API access (through Cordova plugins), and the additional benefits we mentioned from having an app in the store.

While providing hybrid technology for building native-like mobile apps is still our main focus, we have also put substantial effort into our latest version of the Framework, Ionic 4, to make it the platform of choice for building progressive web apps.

In our latest developer survey, 42 percent of developers stated that the PWAs they are building are companion apps to their native counterparts and that 35 percent are thinking about deploying their Ionic apps to the stores as well. PWAs can be a great way to get to market quickly and then rope users into a deeper native experience.

With Ionic, an app can be built for iOS, Android, and as a PWA, all with one codebase—Saving you time, effort, and cost by giving you three platforms for the price of one. To learn more about PWAs and how to get started, check out our resource page with use cases and best practices for progressive web apps.

Read more

© 2019 Extly, CB - All rights reserved.