---
title: "Progressive Web App (PWA) support"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Progressive Web App (PWA) support}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup, message=FALSE, echo=FALSE}
library(shinyMobile)
```

The following book provides more in depth [review](https://unleash-shiny.rinterface.com/mobile-pwa) about PWA support.

<div class="atropos atropos-book">
<div class="atropos-scale">
<div class="atropos-rotate">
<div class="atropos-inner">
<a href="https://www.routledge.com/Outstanding-User-Interfaces-with-Shiny/Granjon/p/book/9780367645267" target="_blank">
<img class="img-fluid" src="https://user-images.githubusercontent.com/18291543/181491295-1a5b498c-e7ee-428c-a1af-c3ee22e35ef5.jpg">
</a>
</div>
</div>
</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/atropos@2.0.2/atropos.min.js"></script>

<script>
  const bookAtropos = Atropos({
    el: '.atropos-book',
    shadow: false
    // rest of parameters
  });
</script>

<br>

PWAs are web applications that are regular web pages or websites, but can appear to the user like traditional applications or native mobile applications. They can be __installed__ on the device, provide __offline__ features, can be __launched from the home screen__, and have a __fullscreen__ display.

<br>

In essence, PWAs are websites. They have the same basic features as any other website: at least one HTML page, which very probably loads some CSS and JavaScript. But a PWA has some additional requirements as well:

- A **manifest**: a JSON file specifying app metadata like its name, icons to use for user’s home screen and launch screen, and theme colors.
- A **service worker** that can cache the app content, thereby making sure to provide basic offline support.

<br>

Luckily, this is can all be handled by `{shinyMobile}` and `{charpente}`.

## Configuration

`{shinyMobile}` is PWA capable, meaning that you can make sure your app uses the correct assets to be used as a PWA. This feature is automatically handled by `f7Page()` if `allowPWA` is `TRUE`. 

<br>

When set to `TRUE`, your app is set up to use both a `service-worker.js` script and a `manifest.webmanifest` file that you will provide.

<br>

To create these necessary assets for your PWA, you can use `{charpente}`:

```r
remotes::install_github("RinteRface/charpente")
library(charpente)
set_pwa(APP_PATH, ...)
```

Where `APP_PATH` is the app location. Currently, it only works if the app is **inside a package** like with [`{golem}`](https://github.com/ThinkR-open/golem). If your app is not in a package, you may copy the `www` folder of the [gallery app](https://github.com/RinteRface/shinyMobile/tree/master/inst/examples/gallery/www), which provides:

- A valid `service-worker.js`.
- A valid web manifest (`manifest-webmanifest`). Don't forget to change the `start_url` property to the path of your app.
- As a bonus a valid `offline.html` fallback, which is displayed when the app is offline.
- A valid set of icons. There are tools such as [appsco](https://appsco.pe/developer/splash-screens) and [app-manifest](https://app-manifest.firebaseapp.com), to create 
those custom icons and splash screens, if you need to.

It is really easier with `{charpente}`, the reason why we strongly recommend to develop your app inside a package.

<br>

But that's not all that's needed! When you set `allowPWA = TRUE` in `f7Page()`, the app will also attach the [Google PWA compatibility script](https://github.com/GoogleChromeLabs/pwacompat), called PWACompat, which will help with PWA compatibility. More specifically, PWACompat brings the Web App Manifest to non-compliant browsers for better PWAs. This mostly means creating splash screens and icons for Mobile Safari, as well as supporting IE/Edge's Pinned Sites feature. It basically assures that the `manifest.webmanifest` file has a wider support.

## Using your PWA

The first step is to deploy your app somewhere. It doesn't matter where (shinyapps.io, Posit Connect, your own server, etc.), but you will need a URL to access it.

<br>

Then, you can follow these steps to install your app on your mobile device.

<br> 
Copy the URL of your app in your mobile web browser (iOS: Safari and Andoid: Chrome). It opens like a classic web app, with top and bottom ugly navigation bars that are part of the browser UI.

- Select the share button located in the bottom bar of your iPhone/iPad For Android, you may do something similar. Importantly, Chrome for iOS does not support this feature, that's why we recommend using Safari.
- Click on "Add to Home Screen"
- Choose a relevant name and click on OK. 
- The app will be added to your iOS/Android Apps. In case you want custom icons, replace the content of the www folder with your own.

<div class="row">
<div class="card">
<a href="#" target="_blank"><img src="figures/f7PWA.png"></a>
</div>
</div>

## Limitations
It is actually quite complex to guarantee that all mobile platforms are supported.
The PWA compatibility script will work in most cases. If not, please open an issue [here](https://github.com/GoogleChromeLabs/pwacompat/issues), to help improving it!
