Building a Desktop App with the RingCentral Embeddable and Electron

Embbnux Ji
RingCentral Developers
5 min readFeb 4, 2020

Recently we released the RingCentral Phone for Linux (Community) which is built with the RingCentral Embeddable and Electron library. In this article, we will show you how to turn a web app into a desktop app with Electron, and also show you how to integrate RingCentral Embeddable into a desktop app.

RingCentral Embeddable is a web widget that we provide for developers to integrate the RingCentral service into their web app. But can we also use the RingCentral Embeddable to build an integration for a desktop app? The solution is the Electron library. Electron is a library that helps developers to build a cross platform desktop app with web technologies like HTML and Javascript.

Prerequisites

  1. RingCentral Embeddable
  2. Electron.js
  3. NPM or Yarn (We assume you have installed node.js > 8)

Create your first Electron project

To create your first Electro project go here.

Init project:

$ yarn init
$ yarn add electron --dev

Add start script in `package.json`:

{
"scripts": {
"start": "electron ."
}
}

And create blank files: main.js and app.html

We will have these three files:

first-electron-app-with-rc-embeddable/
├── package.json
├── main.js
└── app.html

Create your first BrowserWindow:

// in main.js
const { app, BrowserWindow } = require('electron')
let mainWindow;function createMainWindow () {
// Create the browser window.
let mainWindow = new BrowserWindow({
width: 300,
height: 530,
webPreferences: {
nodeIntegration: true
},
show: false, // hidden the window before loaded
})
// and load the index.html of the app.
mainWindow.loadFile('app.html')
// Show the main window when page is loaded
mainWindow.once('ready-to-show', () => {
mainWindow.show();
});
}
app.on('ready', createMainWindow)

Start your app:

$ yarn start

Now you have your first app running on the desktop.

Before we continue, we need to understand the main and renderer processes in Electron. The main.js which manage the desktop app runs in the main process and each BrowserWindow instance is run in its own renderer process. The main process is allowed to access the native app API, such as file system. So HTML files and JS are run on renderer process — they can only access the Web API that we use in the Chrome Browser.

Load RingCentral Embeddable

The RingCentral Embeddable is a web widget hosted on our Github Page or our CDN. You will load the Embeddable widget with `webview` component. You could also load it by `BrowserWindow` directly, but with the `webview` component, we can have a more customized UI.

In app.html:

<html>
<head>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' https://ringcentral.github.io">
<title>RingCentral Embeddable app</title>
<style type="text/css">
// your page styles in here
</style>
</head>
<body>
<div id="app">
<webview
partition="persist:rcstorage"
allowpopups
id="rc-widget-adapter-frame"
src="https://ringcentral.github.io/ringcentral-embeddable/app.html"
>
</webview>
</div>
<script>
// your page JS in here
</script>
</body>
</html>

We now need to set the “Content-Security-Policy”, so we can load the resources from the web page security. Then we need thepartition for webview component — we need this for persistent data storage from the web page.

Use preload to run your JS with RingCentral Embeddable

After loading the RingCentral Embeddable, we need to interact with it. The RingCentral Embeddable is designed for web app, so how can we make it interact with our desktop app?

Electron provides a preload API, we can use this API to insert our customized JS into the web page when it loads. This will let us hack the web to interact with our main process.

Add the preload option into the webview component:

<webview
partition="persist:rcstorage"
preload="./preload.js"
allowpopups
id="rc-widget-adapter-frame"
src="https://ringcentral.github.io/ringcentral-embeddable/app.html"
>
</webview>

Create preload.js in the project root folder:

const { ipcRenderer } = require('electron');window.addEventListener('message', function (event) {
const data = event.data;
if (!data) {
return;
}
let notification;
switch (data.type) {
case 'rc-call-ring-notify':
// get call on ring event
ipcRenderer.send('show-main-window');
const call = data.call;
notification = new Notification('New Call', {
body: `Incoming Call from ${call.fromUserName || call.from}`
});
notification.onclick = () => {
ipcRenderer.send('show-main-window');
};
break;
case 'rc-inbound-message-notify':
const message = data.message;
notification = new Notification('New Message', {
body: `Message from: ${message.from && (message.from.phoneNumber || message.from.extensionNumber)}`,
});
notification.onclick = () => {
ipcRenderer.send('show-main-window');
};
break
default:
break;
}
});

preload.js redirects messages between RingCentral Embeddable and the main process. For example, when the RingCentral Embeddable gets an incoming call, we can send a message to the main process, so that the main process can make a minimized window show up at the top of the window.

For more information on the API and events from the RingCentral Embeddable go here.

Package your app with electron builder

After we finish development of the electron app, we need to package our app so users can install it easily, such as dmg for macOS, deb for debian and ubuntu, exec for Window.

We can use electron-builder to package the app, it supports to package the app for macOS, windows and Linux.

$ yarn add electron-builder --dev

Create `electron-builder.yml`:

appId: com.your_org.integration.your_app_name
productName: Your app name
files:
- package.json
- main.js
- app.html
- preload.js
directories:
buildResources: build
output: release
publish:
-
provider: github
owner: your_github_account
repo: your_github_repo
mac:
category: public.app-category.business
icon: icon.icns
dmg:
contents:
-
x: 130
y: 220
-
x: 410
y: 220
type: link
path: /Applications
win:
target:
- nsis
linux:
target:
- deb
- AppImage
category: Telephony
desktop: rc-ev.desktop

Add scripts command into `package.json`:

{
"scripts": {
"postinstall": "electron-builder install-app-deps",
"start": "electron .",
"package": "electron-builder",
"package-linux": "electron-builder --linux",
"package-release": "electron-builder --linux -p always",
"package-all": "electron-builder -mwl"
},
}

To package for all platforms:

$ yarn package-all

If you add Github information into `electron-builder.yml` publish section. It can help you create a release tag and upload install files into the Github releases. This will allow user to download it from your Github repo releases.

More Information

You can get the full source code here. We have also packaged this app for Linux users, you can go here to download and try it out.

Hopefully this article was helpful. Please let us know what you think by leaving your questions and comments below.

To learn even more about other features we have make sure to visit our developer site and if you’re ever stuck make sure to go to our developer forum.

Want to stay up to date and in the know about new APIs and features? Join our Game Changer Program and earn great rewards for building your skills and learning more about RingCentral!

--

--