The RStudio Shiny web development framework provides a great set of tools to quickly create web applications for scientific and data management use. It is especially good for building user-friendly one-off applications to accomplish specific tasks such as exploring, analyzing or validating data…or producing estimates and reports.
Often the main roadblock when creating shiny applications is not development, but deployment. Shiny webapps can always be run locally from the command line or RStudio, but intended users are typically non-programmers, and may be uncomfortable running scripts. Deploying to low-cost services such as shinyapps.io may not be an option if local databases need to be accessed. Within organizations, deploying small, non-standard projects to a webserver may be difficult or impossible given the inevitable hurdles of IT bureaucracy, security issues, or procurement. When the intended user base is relatively small, creating a standalone program may be the simplest and fastest way to get needed tools into the hands of users…especially when those programs do not require the end-user to have administrative rights in order to install on their local machines.
Unlike scripts that can be subject to errors as the underlying R engine and dependent package universe changes, a standalone application is frozen in time. It will always work as when first constructed. Executable installers cost essentially nothing to copy and distribute. Scaling the user base is a non-issue.
The following steps document one simple and opinionated way to freeze shiny applications for local installs on Windows machines as standalone applications. I have successfully used this method since 2014 and am documenting the steps mostly for myself to avoid forgetting the procedure and repeating common mistakes. It is based on this blog post from 2014 when the shiny framework was still in early development. Next steps are to test and document procedures on how to package standalone shiny apps using Electron on the front-end. See: r-shiny-electron, electricShine, deploy-shiny-electron, electron-quick-start.
-
Create a new shiny application in an RStudio project. Test thorougly to make sure everything works as intended. Include validate() and need() functions liberally to avoid the possibility your application may crash after it has been packaged as a standalone program. Crashes typically require that the offending R process be killed using Windows Task Manager before the program can be restarted…not ideal for end-users. In practice, this is exceedingly rare as long as basic best practices are followed.
-
I normally copy finalized shiny code intended to run standalone over to a separate applications directory. Create a new folder in your applications working directory. In my case this would be
C:\Documents\RStudio\Apps
. For theflight_proof
application used as an example below, the path would be:C:\Documents\RStudio\Apps\flight_proof
-
Download the latest suitable version of R-Portable to the new folder. Then double-click the (currently)
R-Portable_3.6.3.paf.exe
to run. This will create theR-Portable
folder in your new application folder. No admin privileges are needed to installR-Portable
. Although at this writing there is an existingR-Portable_4.0.0_paf.exe
, that version appears to have issues with the Rcpp package. Consequently, until an newer version of R-Portable is released, use the one listed above. -
If a 32-bit version of R is needed to run your application, for example when a 32-bit MS Access database needs to be accessible, do not click
Yes
to theRun R Portable
checkbox during the installation process…as the default assumes you want 64-bit R. -
Install needed R packages, and package dependencies. Normally you would install any required packages by running the
Rgui.exe
located atR-Portable\App\R-Portable\bin\x64
. For the less common cases where 32-bit R is needed I normally navigate to theR-Portable\App\R-Portable\bin\i386
folder and then click onRgui.exe
to open the Rgui. I then install any needed packages using 32-bit R. It may not make any difference either way. -
Using the Rgui (whether 64-bit or 32-bit) open the
library_install.R
script located in the refreeze repository. You will also need thefind_package_dependencies.R
script to do a deep recursive search of all required packages and dependencies. Copies of these scripts are also normally kept in theRStudio\Apps
folder. Run the dependencies script to identify dependencies, then edit the package installation script as needed to add required libraries. -
Copy your
ui.R
,server.R
, andglobal.R
shiny scripts, or any other scripts needed for your application, into a folder namedshiny
in the top-level directory of your application. For example:C:\Documents\RStudio\Apps\flight_proof\shiny
. There should also be awww
subfolder containing any images, rmarkdown .rmd files, etc., directly under theshiny
folder. -
Make sure and edit the
server.R
file to uncomment thestopApp()
function at the very bottom of theserver.R
script. This is needed to make sure theR.exe
is properly closed when the application exits. It is normally commented out during development. The function looks like this:
# close the R session when the browser closes
session$onSessionEnded(function() {
stopApp()
q("no")
})
-
The refreeze repository contains example materials needed for the next steps. Copy the
run.vbs
,runShinyApp.R
, andFlightProof.ico
from the repository into the top level of your app folder. You should also copy theflight_proof.iss
script that will be needed to create the setup executable. I normally keep a copy of all application.iss
scripts in the applications parent directory, in my caseC:\Documents\RStudio\Apps
. -
Rename the
FlightProof.ico
as needed, or find another icon to use. There should be no need to edit the other files. You will only need to editrun.vbs
if 32-bit R is needed. In that case the text of therun.vbs
script will beR-Portable\App\R-Portable\bin\i386\R.exe
instead ofR-Portable\App\R-Portable\bin\x64\R.exe
.
-
Download and install Inno Setup. Then edit a copy of the
flight_proof.iss
Inno Setup script, and rename as needed to your new application name, for example,app_name.iss
. -
Double-click on the
app_name.iss
script to open theInno Setup
program. In theAppID
field, highlight all but the first curly brace, and underTools
click on theGenerate GUID
option. This will overwrite the section with a new GUID. Every time you create a new version, a new GUID should be generated. Edit the other fields as needed to specify things such as the application name and version number, the source directory for the application files, and the destination directory for the setup executable. Make sure that thePrivilegesRequired
field is set tonone
. This will ensure that end-users can run the setup executable without needing administrative privileges. In practice I have found that the setup dialogue may still ask for an administrative login in order to run the installer, but your normal login account name and password will work. -
To create the application setup installer, click on
Build – Compile
. This will bundle up all materials needed for you application and create an executable installer in your application directory. Your application, along with the current version of R and all needed packages, are now frozen in time.
-
When needing to connect to databases, providing connection credentials requires special handling. A secure and relatively foolproof method is to use the
odbc
package, and then set up each user with a DSN. This can be done by typingodbc
into the Windows search bar, then clicking on theODBC Data Sources
application to set up aUser DSN
. Typically, this will be a 64-bit DSN. Connecting via ODBC to aPostgreSQL
database means that you will also need to have the PostgreSQL ODBC driver installed on your computer. -
If you are trying to connect to an
PostgreSQL
database, my current favorite method is to use theRPostgres
package. This may change in the future, but for now it provides better handling of uuids and odd text encodings. It can also be much faster when writing large files.RPostgres
includes it’s own driver, so no separate driver needs to be installed.
-
When connecting via
RPostgres
or other database drivers usingRStudio
, a common way to provide connection credentials such ashost
,username
orpassword
, is to enter the values in an.Renviron
file. You can then use theSys.getenv()
function to pull them out. To make this work withR-Portable
requires some customization. The simplest method is to place the.Renviron
file in theR_HOME
path of yourR-Portable
installation. Then add the following line in your global.R file:readRenviron("C:/data/Apps/FlightProof/R-Portable/App/R-Portable/.Renviron")
. Note that the path includes the name of your application. You can then useSys.getenv()
to pull out any of the variables listed in the.Renviron
file. This will work despite the fact that therun.vbs
file invokesR.exe
using the--vanilla
flag, which instructs R not to read the.Renviron
file. -
A safer method to store credentials is to use your operating system’s credential manager. This functionality can be accessed using the
keyring
package. For Windows users the credentials will then be stored as encrypted values in the Windows Credential Manager. For an example of how this can be implemented using standalone Windows apps, please see theChehalis
andMarSS
repositories. Details can be found in theglobal.R
,server.R
, and files in theconnect
folder.
-
If after installing the application, it crashes, or fails to load, navigate to the
out.txt
folder in the App directory that the installer created, for example:C:\Documents\Intertidal\Apps\FlightProof\out.txt
. Theout.txt
file will log the first fatal error encountered. In the case of missing dependencies it will identify any packages that you may still be missing. Each missing dependency will trigger a crash, so in the past, before using thefind_package_dependencies.R
script, multiple iterations were typically needed to identify all missing package dependencies. Hopefully, this will now be a rare event. -
In case the application crashes or fails to load, you will also most likely need to kill any R processes still active using Windows Task Manager. You will then need to fix the source of the crash, usually a missing package dependency, and recompile the application.