Bringing Impraise Web Application to Mobile

Dorian Amouroux
Impraise Tech and Design
9 min readAug 28, 2020

Actively maintaining native apps is quite costly for a non-mobile-first Start-up. You would need a team committed full time, and eventually double the cost to make sure you cover Android and iOS. Over the last decade, multiple cross-platform solutions appeared, Cordova, React-native, Flutter to name a few. Those solutions are quite popular in start-up environments, enabling them to develop and bring that app to the store in less time and cost than a fully native app could. The main benefits being “write once, run everywhere”.

Context

Impraise is a performance management solution, enabling peers to exchange Feedback using the Praise & Tips feature; helping HR to organize Performance Reviews across teams, departments, or the whole organization, and individuals to record the discussion and action from 1–1s conversation. A lot of our customers and prospects requested to have a mobile experience, from the convenience it can bring, to some users not having a laptop at their workspace (think retail workers).

We decided to go for the “WebView” approach. This solution is powered by an embedded browser, shelled in a native application. This browser would only display the content of the page, but the URL and navigation buttons such as controlling tabs, adding bookmarks, etc will be hidden. This solution at first seemed sub-ideal, as the result we will get is hard to predict, we might end up with an app with janky scrolling, slow animation and far from the standard we set for our product. But given our time and budget constraints, it was worth giving a try.

Disclaimer: While we developed and published applications for both Android and iOS, we will focus on iOS for the code examples and link to the documentation; Android has a similar set of APIs allowing us to implement the solution with the same approach. Also, all the code snippets are drastically simplified for the explanation of the concepts.

Preparing

Our WebApp is fully built using React. Our first milestone was to make the platform responsive. It wasn’t a tough task, as we are using a Design System (check it out!), we simply had to update our structural components to support the mobile view. Some pages needed manual adjustment, which allowed us to also revamp the user experience, by taking a mobile-first approach.

It took us about a quarter of work. It was mainly a mind-shift for the team, as from now on, we had to design, develop, and test every feature for mobile users too. By doing so, we could already bring a mobile experience to our users, as they could use Impraise from their mobile browser. Here are some screenshots of the mobile view of some of our pages:

Profile page — Report of a Review — List of Objectives

After our product was finally responsive, we could start building the native app. We decided to hire a mobile agency (https://itude.com/) who sent us a very competent Mobile developer. We had the requirements that the app must be built once, and give us the chance to update it easily, even without prior mobile development knowledge. So if we want to implement brand-new features that will sit in a new section of the app, we should be able to add it to the navigation ourselves. Push notification should also open the right screen in the application.

Research

We started the project with a design exploration, how to map our existing pages in a way that is convenient for mobile users, we decided to adopt some native components, the top and bottom navigation bar, and use the stack navigation flow, where every screen would open on top of the previous one, and the back button in the top-left corner would dismiss the screen. Here are some screenshots of our exploration:

The home page — Page transition

We decided to have a different home screen than on desktop to facilitate the navigation between the different modules of the applications. The three main sections, Feedback, Goals, and Reviews are accessible via the home screen. The directory of employees, the 1:1s, and the notification center are accessible via the bottom navigation.

It’s possible to ask for feedback from peers via the ‘Ask for feedback’ button. The settings, legal information, and logout are accessible via the top right button ‘Settings’.

We decided to have some parts of the application written natively:

  • The authentication flow (login, magic link, SSO) as it’s a part of the product that won’t change in the foreseeable future.
  • Homepage, as it will be the first screen the user will land on, and it’s a screen that doesn’t exist on the web counterpart.
  • Push notifications as SDKs for the push notifications platforms are usually targeting native applications.

Everything else would be using WebView, rendering our web application. This decision would put us in a good position to get the application store approval while giving us a solid baseline. We can have more control over how the app handles the WebView, how the authentication token is managed, and have the behavior we desire for push notification or deep-link.

Implementation

This design exploration gave us enough information to start investigating what is actually possible to implement. We decided to use the native top and bottom navigation of the platform, which will give the user a sense of familiarity from other applications.

Native VS Web contents — Full screen modal

The button in the top right corner can also hold an action. In the list of goals screen, it’s possible to create a new goal by clicking on the “New goal” button in the top navigation. It will open a modal full screen on the WebView, and hide the native top and bottom navigation.

As those two components will be implemented on the native app, how would we be able to display the right information for the right page? As the native app renders the website in a WebView, how would it know what would be the right title, back button? How can we hook the buttons of the native components to call an action in the WebApp?

On both Android and iOS, the WebView component of the native app can inject some JavaScript code. It can be code to be executed immediately and expose some functions, which when called, will execute a function on the native side. Those two APIs allow bi-directional communication between the WebApp and the native app. They allow us to shift the control from the native application to the WebApp. The native application can expose some functions to control the top and bottom navigation, the WebApp will be able to call them with the right information for each page. It fits right into our requirements, as the WebApp can control the behaviors of those navigation elements, we can modify them by simply updating the WebApp.

After all those investigations on the design and technical possibilities, it was time to get started with the project. Being a product for businesses, the user needs to have an account registered by the admin of their company to use Impraise. There aren’t any public features nor free registration options. We decided to start with the authentication, as it’s the first step the user will go through.

We have a great JSON API to handle login via password, Magic-Link, request a new password, etc. It was quite smooth to integrate it. We could then store the authentication token of the user using NSUserDefaults. This authentication token needs to be attached to any requests to the server. As the WebApp will need it, we inject it in the WebApp:

Simplified code of how we generate the configuration of the WebView

It was important for the app to handle properly the deep links, as Impraise has most of the interaction started by email notification, and open the links of the emails at the right place on the app. As we are using a WebView, it was trivial to implement, by simply passing the URL of the deep-link to the WebView when initialized.

For push notifications, we decided to use the batch.com service to send notifications to the device. We have a micro-service to handle the notifications (in-app notifications, emails, or Slack integrations). We implemented a new adapter on our micro-service to also distribute notifications to batch.com. On the mobile application, it was simply initializing the SDK of batch.com, once the user is authenticated.

The WebApp is responsive, it works on desktop and mobile browsers. It has its own navigation (see the first screenshot) and also a footer. As the native app defines its own navigation, we have to hide the one from the WebApp. To do that, the WebApp must know it is rendered inside a WebView and not in a mobile browser. Once it’s possible to do this check, we can hide the navigation element. It’s possible to inject a custom User Agent with the WebView component. We decided to call it ImpraiseApp and we inject it like so:

Simplified code to set a custom user agent to the WebView

In the WebView app, we can then check on the user agent and hide the navigation element:

Simplified code to hide the Navigation if rendered in a native application

Our application at this stage was already looking great, the user could log in, access the different features of Impraise via the bottom navigation and the home screen. They could participate in different activities from sending feedback, create and update goals, and write some items in 1–1s agenda. The only missing piece is the top navigation of the native app that isn’t controlled by the WebApp yet.

We can easily attach handlers to the WKWebViewConfiguration we created before. We decided to have one handle for each possible configuration on the native elements: one for the left button, one for the title, one for the right button, and one to specify if those elements are visible or not.

We will take the title in the top navigation as it’s the most simple use-case.

Simplified code to expose a handler on the WebView to set the navigation title

On the WebView side, we can now call it to set the title on the page we need it. We create a helper function to set the title of the page and we can call in the components for each page we need to set the title. We are using the hook useLayoutEffect to make sure we set the title when the page is rendered.

Simplified code to call the handle to set the title in the navigation

It was some manual work to go through all of our pages and set the title and buttons. We abstracted it in a single component where we can set all the settings we need. This component also takes care of calling either the iOS or Android handlers depending on the platform, or no handlers, if it’s accessed on a normal browser.

Release

At this point, the application was ready enough to release it internally first. At Impraise, we tried to be the best user of our own product so naturally, most of our coworkers were willing to try the application and give us feedback and find bugs. It really helps us to bring up the quality, as well as helping the other department prepare the material for the release.

--

--